代码之家  ›  专栏  ›  技术社区  ›  Alan

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

  •  19
  • Alan  · 技术社区  · 15 年前

    我有代码可以根据作用域控制互斥锁/解锁:

    void PerformLogin()
    {
        ScopeLock < Lock > LoginLock( &m_LoginLock );
    
        doLoginCommand();
    
        ScopeLock < SharedMemoryBase > MemoryLock( &m_SharedMemory );
    
        doStoreLogin();
    
        ...
    }
    

    我能保证吗 MemoryLock 之前会被摧毁 LoginLock ?

    5 回复  |  直到 14 年前
        1
  •  37
  •   CB Bailey    15 年前

    是的,是的。在任何特定的范围内,局部对象的销毁顺序与它们的构造顺序相反。

        2
  •  11
  •   anon    15 年前

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

        3
  •  11
  •   JaredPar    15 年前

    加上尼尔的回答。

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

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

    如果C++不保证析构函数排序,像这样的直截了当的代码将是非常不安全的,因为在T2的析构函数运行之前,T1可能被破坏。因此,不能保证t2的析构函数使用有效的t1值运行。

        4
  •  3
  •   Reunanen    15 年前

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

    void PerformLogin()
    {
        ScopeLock < Lock > LoginLock( &m_LoginLock );
        doLoginCommand();
    
        {
            ScopeLock < SharedMemoryBase > MemoryLock( &m_SharedMemory );
            doStoreLogin();
            ...
        }
    }
    

    在我看来,这使得意图更加明确。如果您的代码确实是 依靠 在特定的顺序上。我发现这会减少有人不小心更改了顺序,并导致很难找到bug的可能性。(当然,这不是问题,因为我们都有测试,不是吗?)

    我总是把多余的括号写在 (a && b) || c 我也觉得这件事很相似。

    (*):当然,您也可以使用注释。

        5
  •  0
  •   indiv Olivier Poulin    14 年前

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