C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Pointer conversion on call to operator delete()

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Matthias Hofmann
Guest





PostPosted: Sat Dec 20, 2003 7:55 pm    Post subject: Pointer conversion on call to operator delete() Reply with quote



Hello!

I have a question regarding pointer conversion when explicitly calling
operator delete() on a pointer to a class. Consider the following code:

class MyClass {};

void f()
{
MyClass *p = new MyClass;

p->~MyClass();
operator delete( p ); // Converts MyClass* to void*
}

The code should not cause any trouble, as the actual pointer value passed to
operator delete() probably won't change. But imagine the pointer's type is
that of a class which is part of a complex class hierarchy, with multiple
inheritance and all that goes with it. In that case, it might point at a
base class subobject, thus requiring adjustment of the pointer's value
before passing it to operator delete().

I believe that this adjustment is done automatically when operator delete()
is called implicitly in a delete expression. But what if I call operator
delete() explicitly, as in the example above? I have learned that applying a
dynamic_cast<void*> results in a pointer to the complete object - do I have
to do that before calling operator delete(), like in the following example:

class ClassFromComplexHierrachy;

void f( ClassFromComplexHierarchy* p )
{
p->~ClassFromComplexHierarchy();

void* pv = dynamic_cast<void*>( p ); // Get a pointer to the complete
object of *p

operator delete( pv );
}

Or does an implicit conversion also do any necessary adjustment?

Best regards,

Matthias Hofmann




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ron Natalie
Guest





PostPosted: Sun Dec 21, 2003 1:23 am    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote




"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote

Quote:
Hello!

I have a question regarding pointer conversion when explicitly calling
operator delete() on a pointer to a class. Consider the following code:

class MyClass {};

void f()
{
MyClass *p = new MyClass;

p->~MyClass();
operator delete( p ); // Converts MyClass* to void*
}

The code should not cause any trouble,

The code doesn't cause any trouble because MyClass used the default global
allocation and deallocation functions. If MyClass had it's own operator
new
defined, you're calling the wrong one. And there's no programatic way to
tell
what deallocation function to use, that is, you can't just call
MyClass::operator delete
because there may not be one (and then your program will not compile).

Of course, the answer is the above example is insiously stupid. You
shouldn''t
manually attempt to replicate what the delete expression does.

What are you really trying to do?



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Andrea Griffini
Guest





PostPosted: Sun Dec 21, 2003 11:57 am    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote



On 20 Dec 2003 20:23:39 -0500, "Ron Natalie" <ron (AT) sensor (DOT) com> wrote:

Quote:
The code doesn't cause any trouble because MyClass used the default global
allocation and deallocation functions.

Where is stated in the standard that the address of the
memory block returned by "::operator new" will be the address
of the object returned by the "new" operator ?
Can't an implementation add a bit of magic at the
start of the returned memory block ?

If an implementation is not forced to add nothing at the
start of the memory block then calling "::operator new"
with the address returned by the "new" operator (and not
with the one returned by "::operator new") is a recipe
for a disaster.

Andrea

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Potter
Guest





PostPosted: Sun Dec 21, 2003 5:46 pm    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote

On 21 Dec 2003 06:57:44 -0500, Andrea Griffini <agriff (AT) tin (DOT) it> wrote:

Quote:
Where is stated in the standard that the address of the
memory block returned by "::operator new" will be the address
of the object returned by the "new" operator ?

5.3.4/10. The size passed to operator new must be exactly
the size of the object. That applies to any operator new not
just ::operator new. It does not apply to operator new[].

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Matthias Hofmann
Guest





PostPosted: Sun Dec 21, 2003 5:46 pm    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote


Andrea Griffini <agriff (AT) tin (DOT) it> schrieb in im Newsbeitrag:
[email]dtmauv87g5j3sad92nrromfk6lab7fr3qk (AT) 4ax (DOT) com[/email]...
Quote:
On 20 Dec 2003 20:23:39 -0500, "Ron Natalie" <ron (AT) sensor (DOT) com> wrote:

The code doesn't cause any trouble because MyClass used the default
global
allocation and deallocation functions.

Where is stated in the standard that the address of the
memory block returned by "::operator new" will be the address
of the object returned by the "new" operator ?
Can't an implementation add a bit of magic at the
start of the returned memory block ?

The standard guarantees that "magic" may be added for array allocation
(5.3.4/12), and only for array allocation (5.3.4/10). This is done
automatically by the compiler (18.4.1.2 Footnote 211), so the additional
memory required is automatically added to the size argument when passed to
the allocation function.

As 5.3.4/8 states that the new expression calls operator new for single
objects and operator new[] for array, the address of the block of memory
returned by operator new will be the address of the object unless it is an
array. The same goes for class scoped allocation functions, as 3.7.3/3
states that any allocation or deallocation functions in a C++ program must
meet the semantics described in 3.7.3.1 and 3.7.3.2, which deal with
describe the behaviour of allocation and deallocation functions.

Quote:

If an implementation is not forced to add nothing at the
start of the memory block then calling "::operator new"
with the address returned by the "new" operator (and not
with the one returned by "::operator new") is a recipe
for a disaster.


You probably mean "calling ::operator delete with the address returned by
the new operator"...

The problem is a different one, take a look at this code:

struct A {};
struct B {};

struct C : public A, public B
{
void* operator new( std::size_t size, Pool& pool );
void operator delete( void* p, Pool& pool );
};

Pool pool;

void f( B* p )
{
p->~B();
C::operator delete( p, pool );
}

void g()
{
A* p = new( pool ) C;

f( dynamic_cast<B*>( p ) );
}

In g(), the new expression returns the address of an object of type C. When
casting the pointer to a B*, the pointer value might be adjusted to the
address of the base class subobject. Now what does C::operator delete() get
as its first argument in f()? A pointer to the complete object of *p, or a
pointer to the B subobject?

And as we are talking of casts: Would it be possible to call f() without a
dynamic_cast, e.g. a static_cast? I guess that implicit conversion is out of
question, there is no inheritance relationship between A and B.

Best regards,

Matthias Hofmann






[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Matthias Hofmann
Guest





PostPosted: Sun Dec 21, 2003 5:46 pm    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote


Ron Natalie <ron (AT) sensor (DOT) com> schrieb in im Newsbeitrag:
3fe4add7$0$70080$9a6e19ea (AT) news (DOT) newshosting.com...
Quote:


[snip]

Quote:
Of course, the answer is the above example is insiously stupid. You
shouldn''t
manually attempt to replicate what the delete expression does.

What are you really trying to do?


Well, I am actually concerned about the case where MyClass overloads
operator new and operator delete in order to allocate memory from a private
pool, as in the following case:

MyPool pool;

struct MyClass
{
void* operator new( std::size_t size, MyPool& pool );
void operator delete( void* p, MyPool& pool );
};

void f()
{
MyClass* p = new( pool ) MyClass;

p->~MyClass();
MyClass::operator delete( p, pool );
}

MyClass::operator delete() assumes that it is passed the same pointer value
that was returned from MyClass:operator new(). This assumption is probably
made by any deallocation function, so there is no real difference to my
first example, which uses the global versions of operator new and operator
delete.

And this brings me to my question again: Is the pointer passed to operator
delete(), no matter wether the latter is global or class scoped, guaranteed
to be a pointer to the complete object of *p, which should mean the same as
the pointer value returned by operator new()? I am worried about those case
where p points at a base class subobject, whose address might be "somewhere
within" the complete object, if multiple inheritance is involved.

Best regards,

Matthias Hofmann






[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ron Natalie
Guest





PostPosted: Mon Dec 22, 2003 1:16 am    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote


"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote


Quote:
What are you really trying to do?


Well, I am actually concerned about the case where MyClass overloads
operator new and operator delete in order to allocate memory from a private
pool, as in the following case:

That's fine, but the normal and safe way to do this is to just say:
delete p;
rather than trying to simulate it. This will call your class's constructor
and operator delete just fine.

Quote:
I am worried about those case
where p points at a base class subobject, whose address might be "somewhere
within" the complete object, if multiple inheritance is involved.

Your hosed in that case. You're also hosed if you say "delete p".
It is not valid to delete something not allocated by new. That is,
with one small exception saying:
TypeA* ap = new TypeA;
TypeB* bp = SomeHowConvertAtoB(ap);
delete bp;
and it is equally wrong in your "simulation of delete."

The only time you can change the type of the value passed to delete
from what it was at new time is:
1. You are doing a delete on a single object (not delete[]).
2. The type of the pointed to object presented to delete is an accessible base class of
the originally new'd type.
3. The type of the pointed to object has a virtual destructor.

The presence of the virtual destructor tells the delete expression
to watch out for two things:

1. That it needs to invoke the destructor on the derived class.
2. That it needs to check the derived class for different operator delete
function.

I'm still missing why you don't think just using "delete" will work for you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Mon Dec 22, 2003 7:42 pm    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote

"Ron Natalie" <ron (AT) sensor (DOT) com> wrote

Quote:
"Matthias Hofmann" <hofmann (AT) anvil-soft (DOT) com> wrote in message
news:bs4as7$52m$2 (AT) news1 (DOT) nefonline.de...

What are you really trying to do?

Well, I am actually concerned about the case where MyClass overloads
operator new and operator delete in order to allocate memory from a
private pool, as in the following case:

That's fine, but the normal and safe way to do this is to just say:
delete p;
rather than trying to simulate it. This will call your class's
constructor and operator delete just fine.

I am worried about those case where p points at a base class
subobject, whose address might be "somewhere within" the complete
object, if multiple inheritance is involved.

Your hosed in that case. You're also hosed if you say "delete p".
It is not valid to delete something not allocated by new. That is,
with one small exception saying:
TypeA* ap = new TypeA;
TypeB* bp = SomeHowConvertAtoB(ap);
delete bp;
and it is equally wrong in your "simulation of delete."

That's not true. All that is required is that TypeB have a virtual
destructor.

This is actually very frequent. It may be less frequent to want to
separate destruction and freeing memory, but there are cases. (The STL
does it all the time, as did my pre-standard array, list and associative
array classes.) I can't think of any case off hand where I would
separate destruction and freeing memory of polymorphic objects, but I
wouldn't go so far as to say that they cannot exist.

In his case, I think that dynamic_cast will do the trick, *but* it must
be invoked before the destructor is called, e.g.:

MyClass * p = whatever ;

void* pvoid = dynamic_cast< void* >( p ) ;
p->~MyClass() ;
operator delete( pvoid ) ;

And of course, it only works if MyClass has a virtual destructor.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Matthias Hofmann
Guest





PostPosted: Tue Dec 23, 2003 2:06 am    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote


Ron Natalie <ron (AT) sensor (DOT) com> schrieb in im Newsbeitrag:
3fe5f1b8$0$70044$9a6e19ea (AT) news (DOT) newshosting.com...
Quote:


[snip]

Quote:

I'm still missing why you don't think just using "delete" will work for
you.


Because there is no way to provide additional arguments in a delete
expression, so that I can return the memory where it came from (a private
pool for example). However, I have meanwhile learned in another thread that
there is a solution to that:

class CAllocator
{
public:
void* Malloc( std::size_t size ) throw( std::bad_alloc )
{
void* p = malloc( size );

if ( !p ) throw std::bad_alloc();

return p;
}

void Free( void* p )
{
free( p );
}
};

struct A
{
void* operator new( std::size_t size, CAllocator& ra ) throw (
std::bad_alloc )
{
void* p = ra.Malloc( size + sizeof ( CAllocator* ) );

CAllocator** ppa = static_cast<CAllocator**>( p );

*ppa = &ra;

return ppa + 1;
}

void operator delete( void* p, CAllocator& ra ) throw()
{
ra.Free( p );
}

void operator delete( void* p ) throw()
{
CAllocator** ppa = static_cast<CAllocator**>( p ) - 1;

operator delete( ppa, **ppa );
}
};

int main( void )
{
CAllocator a;

A* p = new( a ) A;

delete p; // Hurray!

return 0;
}

This implementation makes it possible to "just use delete". It is
conceptually equivalent to the unpopular

p->~MyClass();
MyClass::operator delete( p, pool );

The only difference now should be that the compiler ensures that the pointer
value passed to operator delete is the same as that returned from operator
new. I was interested wether this value transformation also takes place when
using the "ugly" way of calling the dtor followed by a call to operator
delete - apparently the answer is "no". But this curiosity was the reason
for my original post.

Best regards,

Matthias




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ron Natalie
Guest





PostPosted: Tue Dec 23, 2003 2:10 am    Post subject: Re: Pointer conversion on call to operator delete() Reply with quote


<kanze (AT) gabi-soft (DOT) fr> wrote


Quote:

Your hosed in that case. You're also hosed if you say "delete p".
It is not valid to delete something not allocated by new. That is,
with one small exception saying:
TypeA* ap = new TypeA;
TypeB* bp = SomeHowConvertAtoB(ap);
delete bp;
and it is equally wrong in your "simulation of delete."

That's not true. All that is required is that TypeB have a virtual
destructor.

It is true. Did you see the words "with one small exception" and the
text that immediately follows what I quoted that spefiically describes
the non-array delete of objects via base class pointers. The user
described an arbitrary subobject pointer, which is far more general
than the simple base classs issue.

Quote:
It may be less frequent to want to
separate destruction and freeing memory, but there are cases. (The STL
does it all the time, as did my pre-standard array, list and associative
array classes.) I can't think of any case off hand where I would
separate destruction and freeing memory of polymorphic objects, but I
wouldn't go so far as to say that they cannot exist.

The problem is that there is no way to do this in a way that might work
if the types have overloaded allocation/deallocation functions. The
allocator/deallocators are STATIC functions. Virtual does not apply.
Only delete itself knows how to handle this properly.

The STL does NOT do this. The STL uses it's own memory allocation
and deallocation functions and constructs/destructs objects over the top
of these allocations. I

Quote:
In his case, I think that dynamic_cast will do the trick, *but* it must
be invoked before the destructor is called, e.g.:

MyClass * p = whatever ;

void* pvoid = dynamic_cast< void* >( p ) ;
p->~MyClass() ;
operator delete( pvoid ) ;

And of course, it only works if MyClass has a virtual destructor.

What operator delete is getting called? It's not necessarily the right one!


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.