Destroy and then construct new object using the same variable

懵懂的女人 提交于 2019-11-26 15:26:54

I think the only way to make this really safe to use is to require the called constructor to be noexcept, for example by adding a 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);

Of course this will only work for C++11.

If T's constructor throws on the second construction, you got a problem. If you like brute-force approaches, check this:

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!
  }
}

It even provides the strong exception guarantee!


On a more serious note, it's like stepping on a landmine, knowing it will go off if you move your foot...

And there actually is a way around the undefined behaviour of the double destruction here:

#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
}

If T's construction expression throws, you will double destruct the object, which is UB. Of course, even the desire to do this is indicative of a design failure.

I tried to compile it, but I only dared to run it under debugger. So I took a look at disassembly my old compiler generated (comments are compiler's too):

@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. Since you're doing everything that C++ discourages, I think everyone is forgetting about goto.

Note that after the explicit X.~T() call, and before it is reconstructed1, there would still be double destruction if someone did a goto to before the declaration/initialization of the variable x (even within the inner scope block).

Since you could obviously just document that, I won't go through the hassle of trying to 'fix' this. You could, conceptually, design a RAII class to manages object re-construction in-place, making this manoeuvre safe for goto's in any place. Note that you could have the placement-new constructor call get perfectly forwarded from the RAII manager object's destructor. Life is good.

The other caveats still apply, of course (see other answers)


1 we can assume nothrow constuction for this moment

There is nothing to stop you doing this, it will work in most cases. But as is the case in a lot of C++ knowing the specifics of your your cases will be the difference between it working as you want and a core dump. There are very few example of reasons I could see why you would want to do this in a real program, the only one that make sense is a memory mapped file.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!