我需要明确销毁对象吗?

4

我知道当隐式构造函数为您提供时,您的类成员将从左到右、从上到下进行初始化。换句话说,按照它们被声明的顺序。然后,当类对象超出作用域时,所有成员都会以相反的顺序被销毁。但是如果我必须自己销毁成员,我是否必须按照它们列出的确切顺序进行销毁?例如:

struct Dog {};

struct Animal
{
    Dog* dog1 = new Dog;
    Dog* dog2 = new Dog;
    ~Animal() 
    {
        delete dog2;     // First delete dog2
        delete dog1;     // Then delete dog1
    // Or do I?
    }
};

我认为提供的析构函数是一个空函数。所以当我听到该类将在其超出范围时调用其成员的析构函数时,它并不是在自己的析构函数中实现的,而是在其后使用编译器单独生成的代码来实现?例如:

struct Animal
{
     Dog dog1;
     // ~Animal(){}implicitly defined destructor here. dog1 isn't destroyed here
    // But is destroyed here, or after, or something along those lines with separate code that the compiler generates?

};

感谢您的信任。
4个回答

5
如果我需要自己销毁成员,是否必须按照它们列出的顺序执行?
不是的,您可以按任何顺序执行。
但是我更喜欢匹配“自动”顺序,以免受到惊吓。
提供的析构函数为空。因此,当我听说类会在其超出范围时调用其成员的析构函数时,它不会在其自己的析构函数中执行,而是在之后,使用编译器单独生成的代码?
基本上是这样的。
析构函数体的执行是销毁的一部分。另一部分是销毁所有成员和基类。

我明白了。我开始认为反向销毁只对堆栈上的东西很重要,而不是堆上的东西?我错了吗?编辑:等等,但类对象可以在堆上创建。哦,我很困惑。 - Zebrafish
@TitoneMaurice:这取决于你所说的“重要”是什么意思。 - Lightness Races in Orbit
@TitoneMaurice - 这总是很重要的,特别是如果成员是相互关联的对象。您不希望以错误的顺序破坏它们。 - StoryTeller - Unslander Monica
@StoryTeller:如果它们彼此之间没有关联,那么它就一点也不重要。 - Lightness Races in Orbit
@TitoneMaurice: “我看到甚至有20年的老手说:“我以前从没见过这样的事情”,比如在构造函数周围加上try catch。" 这些人对我来说听起来不像“老手”!尽管可以承认,函数try块并不是很常见。 - Lightness Races in Orbit
显示剩余2条评论

3
请记住,删除指针指向的对象和销毁指针本身之间有区别。当包含对象的生命周期结束时,C++会自动销毁指针本身,并按照它们构造的相反顺序进行销毁。您可以根据对象的设置任意顺序地删除这些指针。
值得注意的是,如果您从使用原始指针更改为使用unique_ptr,那么这将完全由其处理,甚至根本不需要析构函数!

1
您在析构函数中销毁对象的顺序通常并不重要,除非基于拥有的资源需要有某些原因。例如,如果您要删除一个拥有的线程对象,则可能希望确保线程已退出,然后再删除该线程可能使用的项目。shared_ptr和其他智能指针在这些情况下非常有用。它们还有助于减少对析构函数的总体需求。

1
如Orbit所回答的那样,您可以按任意顺序销毁类的成员。但是默认析构函数(如果未显式调用)总是按与创建成员相反的顺序销毁成员。
由于析构函数也是一个函数,因此您可以在该函数中添加语句,在对象销毁时执行这些语句,然后按相反的顺序删除类的成员。
例如:
struct Dog {};

struct Animal
{
    Dog* dog1 = new Dog;
    Dog* dog2 = new Dog;
    int var;

    ~Animal() 
    {
        delete dog1;     // First delete dog1
    }   //delete var and then delete dog2
};

析构函数将执行其主体,然后以相反的顺序开始删除其剩余成员。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接