为什么不删除具有 C++11 中具有副作用的析构函数未定义行为的对象

Why is not deleting an object that has a destructor with a side effect undefined behavior in C++11?

本文关键字:对象 未定义 析构函数 副作用 删除 C++11 为什么不      更新时间:2023-10-16

这个答案引用了C++11标准3.8:

如果没有显式调用析构函数,或者未使用 delete-expression (5.3.5( 来释放存储,则不应隐式调用析构函数,并且依赖于析构函数产生的副作用的任何程序都具有未定义的行为。

关于不调用析构函数的部分很清楚。现在假设跳过的析构函数具有应该影响程序行为的副作用。

为什么现在未定义程序行为?为什么不跳过副作用(因为不调用析构函数(,并且程序在没有应用副作用的情况下正常运行?

重要的部分是该段的第一部分(强调我的(:

程序可以通过重用对象占用的存储来结束任何对象的生命周期......

如果只是对尚未调用析构函数的对象重用存储,则会得到未定义的行为。例如,对象可能已启动线程、注册回调或外部组件可能期望对象仍然存在的某些其他操作。

在这种情况下,我们确实有一个准确的答案。引入该特定行是为了解决CWG 1116"工会成员的别名"。

你的问题没有意义。

为什么不跳过副作用(因为不调用析构函数(,并且程序在没有应用副作用的情况下正常运行?

它们被跳过,因为它们将由析构函数触发,并且尚未调用。

我的阅读:

任何依赖于析构函数产生的副作用的程序都具有未定义的行为。

很简单,我根据 RAII 来看待它。例:

#include "Object.hpp"
struct Manager: private boost::noncopyable {
  union Raw {
    char _[sizeof(Object)];
    Object o;
  };
  static Raw raw;
  Manager() { new (raw.o) Object(); }
  ~Manager() { raw.o.~Object(); }
};

现在,如果我分配一个Manager,忘记销毁它,并分配一个新的,我会陷入困境,因为我正在用第二个覆盖第一个创建的Object的存储,即使它仍然"活着"。这是未定义的行为。

我相信

这已被放入标准中以允许垃圾收集。并指出C++的行为与其他一些语言不同,因为在收集时不调用析构函数。

它特别指出,存储可以重用,而无需调用该内存区域中对象的析构函数。如果程序依赖于正在运行的析构函数,则它将无法按预期工作。

如果它依赖于析构函数,一切都很好。