为什么不删除具有 C++11 中具有副作用的析构函数未定义行为的对象
Why is not deleting an object that has a destructor with a side effect undefined behavior in C++11?
这个答案引用了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++的行为与其他一些语言不同,因为在收集时不调用析构函数。
它特别指出,存储可以重用,而无需调用该内存区域中对象的析构函数。如果程序依赖于正在运行的析构函数,则它将无法按预期工作。
如果它不依赖于析构函数,一切都很好。
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 为什么销毁被放置 new 覆盖的对象不是未定义的行为?
- 未定义的对象(〔basic.life〕/8):为什么允许引用重新绑定(和常量修改)
- 正在通过const-ref未定义的行为捕获新构造的对象
- 仅标头类 + 仅当返回该类的对象时,对函数的未定义引用
- 如果用户尝试从 JS 调用对象的未定义函数C++则回调C++代码
- C++:在共享对象中调用抽象基类构造函数/未定义的符号
- Cython:共享对象中未定义的符号
- 对"车辆的 vtable"的未定义引用 - 面向对象的编程练习
- 为什么内置类型的对象上的溢出会导致异常/未定义的行为?
- 正在加载共享对象:文件中未定义版本Qt_5
- 对象文件中的未定义引用 - 如何查找哪个库包含它
- static_cast实际上不是对象类型的类型是未定义的行为吗?
- 尝试与从 CUDA 对象构建的共享库链接时未定义的符号
- C++ / G++ Maxmind geolite2++ 第三方共享对象未定义引用
- 对象在函数中未定义
- C++ 未定义的对象引用
- 通过在此指针上放置新位置重新初始化对象时未定义的行为
- 无法加载共享对象:未定义的符号
- 模板和静态对象(未定义的引用和必需的引用)