为什么 C++ 默认析构函数不破坏我的对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2403020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:22:49  来源:igfitidea点击:

Why doesn't the C++ default destructor destroy my objects?

c++defaultdestructor

提问by Oszkar

The C++ specification says the default destructor deletes all non-static members. Nevertheless, I can't manage to achieve that.

C++ 规范说默认析构函数删除所有非静态成员。然而,我无法做到这一点。

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

回答by Fred Larson

What makes you think the object npoints to should be deleted by default? The default destructor destroys the pointer, not what it's pointing to.

是什么让您认为n默认情况下应该删除指向的对象?默认析构函数销毁指针,而不是它指向的对象。

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 tpointer is cleaned up, but the Thingit points to is not. This is a leak. Essentially the same thing is happening in your class.

t指针被清理,但Thing它指向的不是。这是泄漏。基本上同样的事情发生在你的课堂上。

回答by P Shved

Imagine something like this:

想象一下这样的事情:

class M {
public:
    M() { }
//  ~M() {        // If this happens by default
//      delete n; // then this will delete an arbitrary pointer!
//  }
private:
    N* n;
};

You're on your own with pointers in C++. No one will automatically delete them for you.

您可以自己使用 C++ 中的指针。没有人会自动为您删除它们。

The default destructor will indeed destroy all member objects. But the member object in this case is a pointer itself, not the thing it points to. This might have confused you.

默认析构函数确实会销毁所有成员对象。但是在这种情况下,成员对象是一个指针本身,而不是它指向的对象。这可能让你感到困惑。

However, if instead of a simple built-in pointer, you will use a smart pointer, the destruction of such a "pointer" (which is actually a class) might trigger the destruction of the object pointed to.

但是,如果您将使用智能指针而不是简单的内置指针,则这种“指针”(实际上是一个类)的销毁可能会触发指向的对象的销毁。

回答by David Thornley

The default destructor is destroying the pointer. If you want to delete the Nwith M's default destructor, use a smart pointer. Change N * n;to auto_ptr<N> n;and nwill be destroyed.

默认析构函数正在销毁指针。如果要删除NwithM的默认析构函数,请使用智能指针。更改N * n;auto_ptr<N> n;n将被销毁。

Edit: As pointed out in comments, auto_ptr<>is not the best smart pointer for all uses, but it looks like what's called for here. It specifically represents ownership: the N in an M is there for the duration of the M and no longer. Copying or assigning an auto_ptr<>represents a change in ownership, which is usually not what you want. If you wanted to pass a pointer from M, you should pass a N *gotten from n.get().

编辑:正如评论中所指出的,auto_ptr<>并不是所有用途的最佳智能指针,但它看起来像这里所要求的。它特别代表所有权:M 中的 N 在 M 的持续时间内存在,不再存在。复制或分配一个auto_ptr<>代表所有权的更改,这通常不是您想要的。如果你想从 M 传递一个指针,你应该传递一个N *got from n.get()

A more general solution would be boost::shared_ptr<>, which will be in the C++0x standard. That can be used pretty much wherever a raw pointer would be used. It's not the most efficient construct, and has problems with circular references, but it's generally a safe construct.

一个更通用的解决方案是boost::shared_ptr<>,它将在 C++0x 标准中。几乎可以在使用原始指针的任何地方使用它。它不是最有效的构造,并且在循环引用方面存在问题,但它通常是一个安全的构造。

Another edit: To answer the question in another comment, the standard behavior of the default destructor is to destroy all data members and base classes. However, deleting a raw pointer simply removes the pointer, not what it points to. After all, the implementation can't know if that's the only pointer, or the important one, or anything like that. The idea behind smart pointers is that deleting a smart pointer will at least lead to the deletion of what it points to, which is usually the desired behavior.

另一个编辑:要回答另一个评论中的问题,默认析构函数的标准行为是销毁所有数据成员和基类。但是,删除原始指针只是删除指针,而不是它指向的内容。毕竟,实现不知道这是唯一的指针,还是重要的指针,或者类似的东西。智能指针背后的想法是,删除智能指针至少会导致其指向的内容被删除,这通常是我们想要的行为。

回答by fredoverflow

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()
    {
    }
};

回答by UncleBens

It is incorrect to say that the destructor deletesmembers. 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).

news 与deletes匹配是您的责任(手动或借助智能指针)。

回答by Anzurio

Your argument might seem sound but that's not how things work for pointers.

您的论点可能听起来很合理,但这不是指针的工作方式。

nis actually being destructed but, what this means is that the N*destructor is being called which, it does NOT destruct whatever object nis 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.

n实际上正在被破坏,但这意味着N*正在调用析构函数,它不会破坏n指向的任何对象。将 theN*的析构函数视为 anint的析构函数。它删除它的值,指针也是如此,它删除它指向的地址,但它不需要删除位于您刚刚删除的地址处的任何对象。

回答by Philip Potter

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 Mis destroyed and M::~M()is called, its variable nreally is destroyed. The problem is that nis a N *, so while the pointer is destroyed, the thing it points to is not.

我认为您可能对这里的间接级别感到困惑。当一个实例被销毁时,每个数据成员确实会随之被销毁。在您的情况下,当 anM被销毁并被M::~M()调用时,它的变量n确实被销毁了。问题是它n是 a N *,所以当指针被销​​毁时,它指向的东西不是。

deletedoes not work like this. Consider your simple statement:

delete不是这样工作的。考虑你的简单陈述:

delete n;

The above statement destroys the thing that npoints to, which is an object of type N. It does not destroy nitself, which is an N *pointer.

上面的语句破坏了n指向的东西,它是一个类型的对象N。它不会销毁n自己,它是一个N *指针。

There is a very good reason that M::~M()does not automatically call delete n;which is this: the Nobject referred to might be shared between several Mobjects, and if one Mwere destroyed, the rest would lose the Nthey were pointing at, leaving horrible dangling pointers everywhere. C++ does not attempt to interpret what you meantto do with your pointers, it just does what you toldit to do.

有一个很好的理由M::~M()不会自动调用delete n;which 是这样的:所N引用的对象可能在多个M对象之间共享,如果一个对象M被销毁,其余的将丢失N它们所指向的对象,到处留下可怕的悬空指针。C ++不尝试解释你的意思你的指针做,它只是做了什么你告诉它做的事。

In short, Mreally 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.

简而言之,M真的是在销毁的时候把它的所有成员都销毁,只是这个销毁没有做你认为它应该做的。如果您想要一个拥有对象所有权并在指针被销毁时销毁它的指针类型,请查看std::auto_ptr.

回答by AshleysBrain

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 npointing to a stack variable? Automatically inserting a delete nwould crash.

默认的析构函数不会插入代码来对指向的东西做任何事情。如果你有n指向一个堆栈变量怎么办?自动插入删除 n会崩溃。

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.

默认析构函数调用类的每个成员(member.~T())的析构函数。对于指针,这是一个无操作(什么都不做),就像 myint.~int() 什么都不做一样,但是对于定义了析构函数的成员类,析构函数被调用。

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 beforethe member variables are destroyed (obviously, otherwise they would not be valid!).

当然,如果定义了析构函数,析构函数中的代码会在成员变量被销毁之前运行(显然,否则它们将无效!)。

回答by Tristram Gr?bener

Try avoiding using pointers. They are last resort elements.

尽量避免使用指针。它们是最后的手段。

class N {
public:
    ~N() {
        std::cout << "Destroying object of type N";
    }
};

class M {
public:
    M() {
       // n = new N; no need, default constructor by default
    }
//  ~M() { //this should happen by default
//      delete n;
//  }
private:
    N n; // No pointer here
};

Then use it this way

然后这样用

main(int, char**)
{
    M m;
}

This will display Destroying object of type N

这将显示 N 类型的销毁对象

回答by Matthieu M.

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.

为什么 ?因为pointer( n) 被破坏,而不是指向的对象*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 newlike in new N()in which case the object is placed on the heap and YOU are reponsible for releasing it at a later time.

您应该记住,与C#或 之类的语言不同Java,在 C++ 中有两种方法可以创建对象:直接N myObject(在堆栈上)或通过newlikenew N()在这种情况下,对象被放置在堆上并且您负责稍后释放它.

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 Pointerif you want it to be automatic.

所以你的析构函数会破坏指针,但不会破坏指向的对象。分配对象而不使用 new (并且不使用指针)或使用 aSmart Pointer如果您希望它是自动的。