显式调用析构函数会导致未定义的行为吗?

EXP*_*XP0 5 c++ destructor undefined-behavior

在我看来,下面的代码(来自一些C++问题)应该导致UB,但它似乎不是.这是代码:

#include <iostream>
using namespace std;
class some{ public: ~some() { cout<<"some's destructor"<<endl; } };
int main() { some s; s.~some(); }
Run Code Online (Sandbox Code Playgroud)

答案是:

some's destructor
some's destructor
Run Code Online (Sandbox Code Playgroud)

我学习了c ++ faq lite,我们不应该显式调用析构函数.我认为在显式调用析构函数后,应该删除对象s.程序完成后会自动再次调用析构函数,它应该是UB.但是,我在g ++上尝试了它,并获得与上述答案相同的结果.

是因为这个类太简单了(不涉及新的/删除)?或者在这种情况下它根本不是UB?

Jam*_*lis 15

行为未定义,因为析构函数被调用两次以用于同一对象:

  • 一旦你明确地调用它
  • 一旦范围结束并且自动变量被销毁

在生命周期结束的对象上调用析构函数会导致每个C++03§12.4/ 6的未定义行为:

如果为生命周期结束的对象调用析构函数,则行为未定义

根据§3.8/ 1调用析构函数时,对象的生命周期结束:

类型对象的生命周期在以下情况T结束:

- 如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者

- 重用或释放对象占用的存储空间.

请注意,这意味着如果您的类有一个简单的析构函数,行为是明确定义的,因为这种类型的对象的生命周期不会结束,直到它的存储被释放,自动变量直到函数结束才会发生.当然,我不知道为什么你会明确地调用析构函数,如果它是微不足道的.

什么是琐碎的析构函数?§12.4/ 3说:

如果析构函数是一个隐式声明的析构函数,并且如果:

- 该类的所有直接基类都有微不足道的析构函数

- 对于类类的所有非静态数据成员(或其数组),每个这样的类都有一个简单的析构函数.

正如其他人所提到的,未定义行为的一个可能结果是您的程序似乎继续正常运行; 另一个可能的结果是你的程序崩溃了.任何事都可能发生,并且没有任何保证.


Jer*_*fin 6

它是未定义的行为 - 但与任何UB一样,一种可能性是它(或多或少)似乎起作用,至少对于某些工作定义.

基本上,您需要(或想要)显式调用析构函数的唯一时间是与placement new结合使用(即,您使用placement new在指定位置创建对象,并使用显式dtor调用来销毁该对象).

  • @Elemental:一个显式的dtor调用本身不是UB--但最有可能两次销毁同一个对象**是**UB.实际上,这是标准(第12.4/14节)中给出的示例:"一旦为对象调用析构函数,该对象就不再存在;如果为生命周期已结束的对象调用析构函数,则行为未定义(3.8).[示例:如果显式调用自动对象的析构函数,并且该块随后以通常调用对象的隐式销毁的方式保留,则行为未定义.]" (3认同)