在堆栈上声明对象时,能否保证析构函数顺序?

时间:2009-08-07 16:53:21

标签: c++ destructor

我有基于范围控制互斥锁定/解锁的代码:

void PerformLogin()
{
    ScopeLock < Lock > LoginLock( &m_LoginLock );

    doLoginCommand();

    ScopeLock < SharedMemoryBase > MemoryLock( &m_SharedMemory );

    doStoreLogin();

    ...
}

我可以保证MemoryLock之前LoginLock会被破坏吗?

5 个答案:

答案 0 :(得分:37)

是的,确实如此。在任何特定范围内,本地对象的破坏顺序与构造它们的顺序相反。

答案 1 :(得分:11)

是的,以相反的构造顺序调用析构函数。

答案 2 :(得分:11)

加上Neil的答案。

考虑相反的情况是否正确,即您无法预测堆栈声明变量的析构函数的顺序。这将使得几乎不可能在堆栈上使用依赖值类型。考虑

void Foo() {
  Type1 t1;
  Type2 t2(&t1);
  ...
}

如果C ++不能保证析构函数的排序,那么像这样的直接代码将是非常不安全的,因为在t2的析构函数运行之前t1可能会被销毁。因此,您无法保证t2的析构函数以有效的t1值运行。

答案 3 :(得分:3)

问题已经回答了,但我想补充一点,我通常习惯写这样的东西:

void PerformLogin()
{
    ScopeLock < Lock > LoginLock( &m_LoginLock );
    doLoginCommand();

    {
        ScopeLock < SharedMemoryBase > MemoryLock( &m_SharedMemory );
        doStoreLogin();
        ...
    }
}

在我看来,这使得意图更清晰(*)。如果您的代码确实依赖特定订单,那么这可能是相关的。我发现这使得人们不太可能意外地改变顺序,并导致难以发现的错误。 (嗯,这当然不是问题,因为我们都有测试,不是吗?)

我总是用(a && b) || c之类的东西写出冗余的括号,我发现这个问题非常相似。

(*):当然,您也可以使用评论。

答案 4 :(得分:0)

是的,析构函数与构造函数相反。因为析构函数用于删除不再需要的对象,并且构造函数用于创建对象。