我知道显式调用析构函数会导致未定义的行为,因为双重析构函数调用,就像下面这样:
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
return 0; // Oops, destructor will be called again on return, double-free.
}
但是,如果我们调用placement new来“复活”对象呢?
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
new (&foo) std::vector<int>(5);
return 0;
}
更正式地说:
new
分配的),然后,在这个对象被析构之前,对它调用placement new来“恢复”它?示例用例(尽管这个问题更多的是关于好奇心):我想“重新分配”一个没有operator=
的对象。
我见过this members,它说“覆盖”具有非静态const
成员的对象是非法的。因此,让我们将这个问题的范围限制在没有任何const
成员的对象上。
发布于 2017-03-05 02:01:24
首先,[basic.life]/8
明确指出,在本例中,任何指向原始foo
的指针或引用都应该引用您在foo
中构造的新对象。此外,名称foo
将引用在那里构造的新对象(也称为[basic.life]/8
)。
其次,在退出其作用域之前,必须确保存在存储用于foo
的原始类型的对象;因此,如果抛出任何异常,您必须捕获它并终止程序([basic.life]/9
)。
总体而言,这个想法往往很诱人,但几乎总是一个可怕的想法。
- (8.1) the storage for the new object exactly overlays the storage location which the original object occupied, and
- (8.2) the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
- (8.3) the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
- (8.4) the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).
有理由手动运行析构函数并进行新的放置。像operator=
这样简单的东西并不是其中之一,除非你正在编写自己的/any/vector或类似的类型。
如果你真的,真的想重新分配一个对象,找到一个std::optional
实现,并使用它来创建/销毁对象;这是非常小心的,而你几乎肯定不会足够小心。
发布于 2017-03-05 01:52:48
这不是一个好主意,因为如果新对象的构造函数抛出异常,您仍然可以运行析构函数两次。也就是说,析构函数将始终在作用域的末尾运行,即使您异常地离开作用域。
下面是一个演示此行为的示例程序(Ideone link):
#include <iostream>
#include <stdexcept>
using namespace std;
struct Foo
{
Foo(bool should_throw) {
if(should_throw)
throw std::logic_error("Constructor failed");
cout << "Constructed at " << this << endl;
}
~Foo() {
cout << "Destroyed at " << this << endl;
}
};
void double_free_anyway()
{
Foo f(false);
f.~Foo();
// This constructor will throw, so the object is not considered constructed.
new (&f) Foo(true);
// The compiler re-destroys the old value at the end of the scope.
}
int main() {
try {
double_free_anyway();
} catch(std::logic_error& e) {
cout << "Error: " << e.what();
}
}
这将打印:
以0x7fff41ebf03f构造的
销毁于0x7fff41ebf03f
销毁于0x7fff41ebf03f
错误:构造函数失败
https://stackoverflow.com/questions/42598915
复制相似问题