即使在同一类型上,是否应该使用 placement new 调用析构函数
should the destructor be called with placement new even on the same type
#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 时是否应该始终调用析构函数,或者在某些情况下不应调用析构函数?
What I know is that the destructor should always be called when placement new is used.
是的,除非类型可以轻易破坏。
在这种情况下,必须销毁之前构建的对象before 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();
它在 C++ 标准中明确指定
[basic.life]
5 A program may end the lifetime of any object by reusing the
storage which the object occupies or by explicitly calling the
destructor for an object of a class type with a non-trivial
destructor. For an object of a class type with a non-trivial
destructor, the program is not required to call the destructor
explicitly before the storage which the object occupies is reused or
released; however, if there is no explicit call to the destructor or
if a delete-expression is not used to release the storage, the
destructor shall not be implicitly called and any program that depends
on the side effects produced by the destructor has undefined behavior.
关于未定义行为的可能性,最后一句话留下了一点回旋余地1。但最终,唯一定义明确的类型是析构函数真正微不足道的类型。
1 - 无论如何,截至撰写本文时。
#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 时是否应该始终调用析构函数,或者在某些情况下不应调用析构函数?
What I know is that the destructor should always be called when placement new is used.
是的,除非类型可以轻易破坏。
在这种情况下,必须销毁之前构建的对象before 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();
它在 C++ 标准中明确指定
[basic.life]
5 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
关于未定义行为的可能性,最后一句话留下了一点回旋余地1。但最终,唯一定义明确的类型是析构函数真正微不足道的类型。
1 - 无论如何,截至撰写本文时。