The C++ specification says the default destructor deletes all non-static members. Nevertheless, I can\'t manage to achieve that.
I have this:
class N
Your argument might seem sound but that's not how things work for pointers.
n
is actually being destructed but, what this means is that the N*
destructor is being called which, it does NOT destruct whatever object n
is pointing to. Think of the N*
's destructor as if it were an int
's destructor. It deletes its value, the same happens for a pointer, it deletes the address it is pointing to, but it doesn't need to delete whatever object is located at the address you just deleted.
It is incorrect to say that the destructor deletes members. It invokes the destructor of each member (and base class), which for built-in types (like pointers) means doing nothing.
Matching news with deletes is your responsibility (either manually, or with the help of smart pointers).
Is there any reason why you use a pointer when the pointed-to object seems to belong the contained object? Just store the object by value:
class M
{
N n;
public:
M() : n()
{
}
};
What makes you think the object n
points to should be deleted by default? The default destructor destroys the pointer, not what it's pointing to.
Edit: I'll see if I can make this a little more clear.
If you had a local pointer, and it went out of scope, would you expect the object it points to to be destroyed?
{
Thing* t = new Thing;
// do some stuff here
// no "delete t;"
}
The t
pointer is cleaned up, but the Thing
it points to is not. This is a leak. Essentially the same thing is happening in your class.
I think you may be confused about levels of indirection here. When an instance is destroyed, each data member does indeed get destroyed along with it. In your case, when an M
is destroyed and M::~M()
is called, its variable n
really is destroyed. The problem is that n
is a N *
, so while the pointer is destroyed, the thing it points to is not.
delete
does not work like this. Consider your simple statement:
delete n;
The above statement destroys the thing that n
points to, which is an object of type N
. It does not destroy n
itself, which is an N *
pointer.
There is a very good reason that M::~M()
does not automatically call delete n;
which is this: the N
object referred to might be shared between several M
objects, and if one M
were destroyed, the rest would lose the N
they were pointing at, leaving horrible dangling pointers everywhere. C++ does not attempt to interpret what you meant to do with your pointers, it just does what you told it to do.
In short, M
really is destroying all of its members when it is destroyed, it's just that this destruction doesn't do what you think it should do. If you want a pointer type which takes ownership of an object and destroys it when the pointer is destroyed, look at std::auto_ptr
.
The default destructor looks like this:
~M()
{
}
The default destructor does not insert code to do anything with pointed-to things. What if you had n pointing to a stack variable? Automatically inserting a delete n would crash.
The default destructor calls the destructor on each member of the class (member.~T()). For a pointer, that's a no-op (does nothing), just like myint.~int() does nothing, but for member classes with defined destructors, the destructor is called.
Here's another example:
struct MyClass {
public:
MyClass() { .. } // doesn't matter what this does
int x;
int* p;
std::string s;
std::vector<int> v;
};
The default destructor in reality is doing this:
MyClass::~MyClass()
{
// Call destructor on member variables in reverse order
v.~std::vector<int>(); // frees memory
s.~std::string(); // frees memory
p.~int*(); // does nothing, no custom destructor
x.~int(); // does nothing, no custom destructor
}
Of course, if you define a destructor, the code in your destructor runs before the member variables are destroyed (obviously, otherwise they would not be valid!).