使用相同的变量销毁然后构造新对象

Ker*_* SB 28 c++ placement-new

有时重新开始很好.在C++中,我可以使用以下简单的操作:

{

    T x(31, Blue, false);

    x.~T();                        // enough with the old x

    ::new (&x) T(22, Brown, true); // in with the new!

    // ...
}
Run Code Online (Sandbox Code Playgroud)

在范围的最后,析构函数将再次运行,一切似乎都很好.(我们也说T有点特别,不喜欢被分配,更不用说交换了.)但有些东西告诉我,摧毁一切并再试一次并不总是没有风险.这种方法有可能存在吗?

Gri*_*zly 28

我认为使这个真正安全的唯一方法是要求被调用的构造函数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);
Run Code Online (Sandbox Code Playgroud)

当然这只适用于C++ 11.

  • 非常好用`noexcept` - 我从未意识到它可以被疑问使用! (7认同)

Xeo*_*Xeo 17

如果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!
  }
}
Run Code Online (Sandbox Code Playgroud)

它甚至提供强大的异常保证!


更严重的是,它就像踩着地雷一样,知道如果你移动你的脚就会熄灭它...

还有其实在这里的双重破坏的未定义行为方式:

#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
}
Run Code Online (Sandbox Code Playgroud)

  • @GMan:那部分更像是一个幽默的答案,这就是为什么`(; _;)`表情符号.:)此外,将为实现保留一个`_`宏.:( (7认同)
  • 为什么要使用`_`?`for(;;)` 被定义为无限循环。 (2认同)
  • @Xeo:我明白了,继续吧.:)☆☆☆ (2认同)

Pup*_*ppy 9

如果T的构造表达式抛出,则会双重破坏对象,即UB.当然,即使这样做的愿望也表明设计失败.


lap*_*apk 7

我试着编译它,但我只敢在调试器下运行它.所以我看看我的旧编译器生成的反汇编(注释也是编译器):

@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... 
Run Code Online (Sandbox Code Playgroud)