销毁,然后使用相同的变量构造新对象
Destroy and then construct new object using the same variable
有时重新开始很好。在C++中,我可以使用以下简单的操作:
{
T x(31, Blue, false);
x.~T(); // enough with the old x
::new (&x) T(22, Brown, true); // in with the new!
// ...
}
在作用域结束时,析构函数将再次运行,一切似乎都很好。(也可以说T
有点特别,不喜欢被分配,更不用说交换了。)但有一件事告诉我,摧毁一切并再试一次并非总是没有风险的。这种方法可能有陷阱吗?
我认为让它真正安全使用的唯一方法是要求被调用的构造函数为noexcept
,例如添加static_assert
:
static_assert(noexcept(T(22, Brown, true)), "The constructor must be noexcept for inplace reconstruction");
T x(31, Blue, false);
x.~T();
::new (&x) T(22, Brown, true);
当然,这只适用于C++11。
如果T
的构造函数抛出第二个构造,则会出现问题。如果你喜欢暴力方法,请查看以下内容:
T x(31, Blue, false);
x.~T();
const volatile bool _ = true;
for(;_;){
try{
::new (&x) T(22, Brown, true);
break; // finally!
}catch(...){
continue; // until it works, dammit!
}
}
它甚至提供了强大的异常保证!
更严重的是,这就像踩在地雷上,知道如果你移动你的脚,地雷就会爆炸。。。
实际上,有一种方法可以绕过双重破坏的未定义行为:
#include <cstdlib>
T x(31, Blue, false);
x.~T();
try{
::new (&x) T(22, Brown, true);
}catch(...){
std::exit(1); // doesn't call destructors of automatic objects
}
如果T的构造表达式抛出,则将对对象进行双重析构,即UB。当然,即使是这样做的愿望也表明了设计的失败。
我试图编译它,但我只敢在调试器下运行它。所以我看了一下我的旧编译器生成的反汇编(注释也是编译器的):
@1 sub nerve.cells, fa0h
@2 xor x, x // bitch.
@3 mov out, x
@4 test out, out
@5 jne @1
@6 xor x, x // just in case.
@7 sub money, 2BC // dammit.
@8 mov %x, new.one
@8 cmp new.one, %x
@9 jne @7
...
@25 jmp @1 // sigh...
Mmm。由于您正在做C++不鼓励的事情,我想每个人都忘记了转到。
请注意,在显式X.~T()
调用之后,在重构1之前,如果有人在变量x的声明/初始化之前执行goto
(甚至在内部作用域块内),则仍将存在双重破坏。
既然你显然可以把它记录下来,我就不会再麻烦地试图"解决"这个问题了。从概念上讲,您可以设计一个RAII类来管理对象的重新构建,使这种操作在任何地方都对后藤来说都是安全的。请注意,您可以让placement新构造函数调用从RAII管理器对象的析构函数得到完美的转发。生活是美好的。
当然,其他注意事项仍然适用(见其他答案)
1我们可以假设此时的另一个行构造
没有什么可以阻止你这样做,它在大多数情况下都会起作用。但是,正如许多C++的情况一样,知道你的案例的细节将是它按你想要的方式工作和核心转储之间的区别。我能理解为什么你想在一个真实的程序中这样做的原因的例子很少,唯一有意义的是内存映射文件。
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- C++ 如何在将新对象分配给另一个对象时创建新对象
- 是什么让放置新调用对象的构造函数?
- 放置派生C++的新基子对象
- 重用对象与创建新对象
- 为指向C++中的对象/对象的指针分配堆内存
- thread_local 和 std::future 对象 - 对象的生存期是多少
- 使用矢量中的现有对象,如果C++中不存在,则创建新的对象
- 如何删除分配了新的对象
- C 将HEAP对象插入std ::用insert()插入映射,而另一个则存在删除新的对象
- 使用新的对象
- 使用C++0x std::thread调用新ed对象中的成员函数
- 新的新类对象的函数;错误:非静态成员引用必须相对于特定对象
- C++ 没有新返回对象的算术运算符
- 如何在每次迭代中创建一个新变量/对象的循环
- 如何在Cython中返回新的c++对象
- 如何在不'new'的情况下将新的对象实例添加到 std::list
- 使用“放置新”转移对象所有权
- 将两个复杂的属性重新组合成新的对象