在什么情况下不会调用C++析构函数?

Wil*_*mKF 43 c++ destructor signals exception exit

我知道我的析构函数在堆栈的正常展开时调用,并且在抛出异常时调用,但是在调用exit()时调用.

还有其他情况我的析构函数不会被调用吗?信号如SIGINT或SIGSEGV怎么样?我认为对于SIGSEGV,它们不会被调用,但对于SIGNINT它们是,我怎么知道哪些信号将展开堆栈?

还有其他情况不会被召唤吗?

sti*_*472 48

是否有任何其他情况下他们的[析构函数]不会被调用?

  1. 跳远:这些会干扰自然堆栈展开过程,并且经常导致C++中的未定义行为.
  2. 过早退出(你已经指出了这些,虽然值得注意的是,由于异常被抛出而已经堆叠展开导致未定义的行为,这就是我们永远不应该抛出dtors的原因)
  3. 从构造函数中抛出不会为类调用dtor.这就是为什么,如果你在ctor中分配由几个不同指针(而不是智能指针)管理的多个内存块,你需要使用函数级try块或避免使用初始化列表并在ctor中有一个try/catch块body(或者更好的是,只使用像scoped_ptr这样的智能指针,因为到目前为止,在初始化程序列表中成功初始化的任何成员都将被销毁,即使不会调用类dtor).
  4. 正如所指出的,当通过基指针删除类时未能使dtor成为虚拟,可能无法调用子类dtors(未定义的行为).
  5. 未能为运算符new/new []调用调用匹配运算符delete/delete [](未定义的行为 - 可能无法调用dtor).
  6. 在deallocate部分中使用带有自定义内存分配器的placement new时,无法手动调用dtor.
  7. 使用memcpy这样的函数,只能将一个内存块复制到另一个内存块而不调用copy ctors.mem*函数在C++中是致命的,因为它们推翻了类的私有数据,覆盖了vtable等.结果通常是未定义的行为.
  8. 在不完整类型上实例化某些智能指针(auto_ptr),请参阅此讨论

  • 不错的列表,但是第3点有一个缺陷:你实际上可以在初始化列表周围放置一个try块,查找函数级别的try块:`struct X {X()try:x_(42){} catch(.. .){} private:int x_; 实际上你可以将它用于任何函数,比如`void foo()try {} catch(...){}`但是一些重要的编译器(VS2008,不知道这是否在以后的版本中得到修复)阻塞它.关于智能指针的建议仍然有效. (4认同)

小智 7

C++标准没有提到具体如何信号必须被处理-很多实现可能不支持SIGINT等,如果析构函数不会被调用exit()abort()terminate()调用.

编辑:我刚刚通过C++标准进行了快速搜索,我找不到任何指定信号如何与对象生命周期交互的东西 - 也许有一个比我更好的标准的人能找到一些东西?

进一步编辑:在回答另一个问题时,我在标准中找到了这个:

在从范围退出(但是已完成)时,将为所有具有自动存储持续时间(3.7.2)(命名对象或临时值)的构造对象调用析构函数(12.4),这些对象在其范围内声明,其声明的顺序与其声明的顺序相反.

因此,似乎必须在收到信号时调用析构函数.

  • 你想说什么?问题还在于信号. (4认同)