Why doesn't the C++ default destructor destroy

2019-03-12 06:12发布

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 {
public:
    ~N() {
        std::cout << "Destroying object of type N";
    }
};

class M {
public:
    M() {
        n = new N;
    }
//  ~M() { //this should happen by default
//      delete n;
//  }
private:
    N* n;
};

Then this should print the given message, but it doesn't:

M* m = new M();
delete m; //this should invoke the default destructor

13条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-03-12 06:52

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!).

查看更多
smile是对你的礼貌
3楼-- · 2019-03-12 06:52

I think you could benefit from a very simple example:

int main(int argc, char* argv[])
{
  N* n = new N();
} // n is destructed here

This will not print anything either.

Why ? Because the pointer (n) is destructed, not the object pointed to *n.

Of course, you would not want it to destroy the object pointed to:

int main(int argc, char* argv[])
{
  N myObject;
  {
    N* n = &myObject;
  } // n is destructed here, myObject is not

  myObject.foo();
} // myObject is destructed here

You should remember that unlike languages like C# or Java, there are 2 ways to create objects in C++: directly N myObject (on the stack) or via new like in new N() in which case the object is placed on the heap and YOU are reponsible for releasing it at a later time.

So your destructor destroys the pointer, but not the object pointed to. Allocate the object without new (and without using a pointer) or use a Smart Pointer if you want it to be automatic.

查看更多
女痞
4楼-- · 2019-03-12 06:56

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.

查看更多
Viruses.
5楼-- · 2019-03-12 07:00

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.

查看更多
男人必须洒脱
6楼-- · 2019-03-12 07:03
class N {
public:
    ~N() {
        std::cout << "Destroying object of type N";
    }
};

class M {
public:
    M() {
        n = new N;
    }
//  ~M() { //this should happen by default
//      delete n;
//  }
private:
    N* n;
};

and now the expectation is :

M* m = new M();
delete m; //this should invoke the default destructor

It will only happen, if the class M is derived from N:

class M: Class N {
...

Only in this situation,

M* m = new M()

will call constructor of N and then constructor of M, where as

delete m;

will automatically call destructor of M first and then N

查看更多
ら.Afraid
7楼-- · 2019-03-12 07:04

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()
    {
    }
};
查看更多
登录 后发表回答