对象数组的销毁顺序

时间:2009-11-23 08:33:15

标签: c++

class MyClass
{
};

void foo
{
    MyClass arr[10]; 
}

我想知道函数返回时数组对象的破坏顺序。

我读了关于它的更有效的C ++,它说反向调用析构函数 按如下顺序排列构造函数:

for(int i = 9 ; i >= 0 ;i--)
{
    arr[i].MyClass::~MyClass();
}

有人可以告诉我它的原因吗?

5 个答案:

答案 0 :(得分:2)

这是C ++的析构函数invokation filosophy的逆序的延续。当堆栈分配的对象被销毁时,它以相反的顺序完成以促进RAII。虽然这对于数组元素来说并不是必需的(它们都是使用默认构造函数构造的,并且任何构造/破坏的顺序都可以),但为了保持一致性,它们也是如此。

答案 1 :(得分:2)

您在更有效的C ++中引用的信息适用于包含其他几个对象的对象,如本例所示:

class Foo {
  private:
     Bar bar_1;
     Bar bar_2;

  public:
     Foo() : bar_1(), bar_2() {}
};

在上面的示例中,您将首先构建bar_1,然后是bar_2。当类Foo的对象被销毁时,bar_2首先被销毁,然后被bar_1销毁。这就是斯科特迈耶斯所指的。

从类的角度来看,一个条形数组将是编译器需要销毁的另一个对象,因此破坏的顺序会影响数组在类中其他对象的上下文中被破坏的时间。 / p>

关于数组元素被破坏的顺序,如果这是依赖于实现的话,我不会太惊讶。您还将在此处进行优化(例如,可以通过释放其内存来销毁POD阵列,因为可以是仅由POD组成的对象)。以上所有都会影响数组元素的销毁顺序。

我很想知道你为什么需要知道数组元素被销毁的顺序(除了技术好奇心,这是恕我直言的正当理由)。如果是因为数组元素之间存在依赖关系,我认为数据结构可能需要重新审核。

答案 2 :(得分:1)

任何订单都可以。两个显而易见的选择当然是按顺序或相反顺序。但是,在这种情况下,没有一个编译器制造商认为保留这种依赖于实现的方法是值得的。因此,选择强制执行相反的顺序(如同尖锐的说法,延伸通常的LIFO行为)

答案 3 :(得分:0)

也许构成数组的对象放在堆栈中的顺序。无论如何,除了好奇心,我认为没有理由担心破坏秩序。

答案 4 :(得分:0)

你没有引用你所指的Meyer书中的哪一页,但我同意Timo Geusch的说法听起来好像是指根据继承调用构造函数和析构函数。

对于一个对象实例数组,对象被销毁的顺序是构造顺序的倒数。这很容易验证,如下面的代码所示。类变量跟踪创建的实例总数,每个对象的数据成员跟踪其自己的编号。构造函数和析构函数会打印一条消息,因此在运行时我们可以确切地看到发生了什么以及何时发生。

测试代码在构造时打印出从0到9的对象计数,然后在破坏实例时从9向下打印到0。 (这是在Mac OS X上使用g++-4.2测试的。)

#include <iostream>

class MyClass
{
public:

    MyClass()
    {
        mCounter = kInstanceCount++;
        std::cout << "+++ MyClass() " << mCounter << std::endl;
    }

    ~MyClass()
    {
        std::cout << "--- MyClass() " << mCounter << std::endl;
    }

private:
    unsigned            mCounter;
    static unsigned     kInstanceCount;
};

unsigned MyClass::kInstanceCount = 0;

int main()
{
    MyClass arr[10];
    return 0;
}

您需要检查C ++标准,因为我不是100%确定这不是实现细节(通常是这种情况),在这种情况下您不希望依赖此行为。< / p>

另请注意,创建基于堆栈的实际对象实例数组并不常见。您更有可能使用std::vector,或者使用智能指针来堆分配对象。