#include <new>
struct X
{
~X() { std::cout << "destroyed" << std::endl; }
int x;
};
int main(int argc, const char * const * const argv)
{
X x{1};
new (&x) X{2};
std::cout << x.x << std::endl;
return 0;
}
输出
2
destroyed
我知道的是,在使用placement new时应始终调用析构函数。但是,在此示例代码中,析构函数在main的末尾隐式调用,因此再次调用它是未定义的行为。 所以现在我想知道在使用placement new时是否应该始终调用析构函数,或者在某些条件下不应该调用析构函数?
答案 0 :(得分:2)
我知道的是,在使用placement new时应始终调用析构函数。
是的,除非类型是微不足道的。
在这种情况下,必须在放置新位置之前销毁先前构造的对象:
X x{1};
x.~X();
try {
new (&x) X{2};
} catch(...) {
std::abort(); // no way to recover
}
不可破坏类型的自动变量在破坏状态下一定不能超出范围。如果构造函数抛出异常,则该行为将是不确定的。不建议重用非平凡对象的内存。
重用琐碎对象的内存更安全:
alignas(alignof(X)) std::byte arr[sizeof(X)];
new (arr) X{2};
x.~X();
答案 1 :(得分:2)
它在C ++标准中明确指定
[基本生活]
5程序可以通过重用 对象占用的存储空间或通过显式调用 具有非平凡的类类型的对象的析构函数 析构函数。对于具有非平凡的类类型的对象 析构函数,不需要程序调用析构函数 在对象占用的存储之前明确地重用或 释放但是,如果没有显式调用析构函数或 如果不使用delete-expression释放存储,则 不应隐式调用析构函数,并且依赖于任何程序 析构函数产生的副作用具有不确定的行为。
最后一句话为不确定行为 1 的可能性留出了一些麻烦的余地。但最终,唯一可以明确定义的类型是那些析构函数真正无关紧要的类型。
1 -无论如何,在撰写本文时。