Q about delete

  • Thread starter Gonçalo Rodrigues
  • Start date
G

Gonçalo Rodrigues

Hi all,

I am a little confused about the delete operator, so I have a
question. Suppose we have something like

class Base {
public:
void* operator new(std::size_t size);
void operator delete(void* ptr);

//The rest goes here.
}

class Derived : public Base {
public:
void* operator new(std::size_t size);
void operator delete(void* ptr);

//The rest goes here.
}


Derived* der = new Derived;

Base* base = der; //Implicit upcast.

delete base;


In this case, it is the static type of the pointer that matters, so it
is the Base delete operator that gets called. In fact, by the time
delete is called the object has already been "demoted" to void* -
there is no concept of dynamic type to speak of. Am I correct?

And if the answer is yes, how do I organize things such that the
Derived delete gets called?

The use case I have is of a single-root hierarchy of heap-allocated
objects handled via smart pointers. The root operator new and delete
is just a general-purpose allocator but each class can have (and it
often does) its own special allocators.

TIA, best regards,
G. Rodrigues
 
M

mlimber

Gonçalo Rodrigues said:
I am a little confused about the delete operator, so I have a
question. Suppose we have something like

class Base {
public:
void* operator new(std::size_t size);
void operator delete(void* ptr);

//The rest goes here.
}

You need at least a semicolon, a virtual destructor (see
http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7),
a "static" on each operator, and a size_t parameter to your delete
operator. However, as _C++ Coding Standards_ Item 46 notes, if you
provide any class-specific form of new and delete, you should provide
all of them (plain, in-place, and non-throwing) since they will be
hidden otherwise and since the STL uses the in-place operator
extensively. They can be forwarding functions to the global versions
or, if the base class implements them, "using" declarations.
class Derived : public Base {
public:
void* operator new(std::size_t size);
void operator delete(void* ptr);

//The rest goes here.
}

You need a semicolon, "static" on each operator, and a size_t parameter
to your destructor, but more likely you want:

using Base::eek:perator new;
using Base::eek:perator delete;
Derived* der = new Derived;

Base* base = der; //Implicit upcast.

delete base;


In this case, it is the static type of the pointer that matters, so it
is the Base delete operator that gets called. In fact, by the time
delete is called the object has already been "demoted" to void* -
there is no concept of dynamic type to speak of. Am I correct?

Base's will be called, but the size_t parameter to the destructor will
be correct as long as you have a virtual destructor in your base class.
Stroustrup deals with this very example in section 15.6 of _TC++PL_ 3rd
ed.
And if the answer is yes, how do I organize things such that the
Derived delete gets called?

Delete a Derived pointer, or preferably, use the size_t parameter to
enable the Base class's delete operator to handle freeing any block
that is passed to it (the operator isn't calling the destructor after
all; it's just freeing the memory after the object has already been
destructed) and use the base class's operators in the derived class.

You might also be interested in this FAQ, which deals with memory
pooling:

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14

Cheers! --M
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,150
Latest member
MakersCBDReviews
Top