29

最初からやり直すのが良い場合もあります。C ++では、次の簡単な操作を使用できます。

{

    T x(31, Blue, false);

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

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

    // ...
}

スコープの最後で、デストラクタが再度実行され、すべてが正常に表示されます。(またT、少し特別で、割り当てられるのは好きではありません。交換は言うまでもありません。)しかし、すべてを破壊して再試行することは必ずしもリスクがないわけではないということを教えてくれます。このアプローチで問題が発生する可能性はありますか?

4

6 に答える 6

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);

もちろん、これはC++11でのみ機能します。

于 2012-01-12T03:22:20.767 に答える
17

Tのコンストラクターが2番目の構文をスローする場合、問題が発生します。ブルートフォースアプローチが好きな場合は、これを確認してください。

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
}
于 2012-01-12T02:59:34.423 に答える
9

Tの構築式がスローされた場合、オブジェクトであるUBを二重に破棄します。もちろん、これを実行したいという願望でさえ、設計の失敗を示しています。

于 2012-01-12T02:59:48.480 に答える
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... 
于 2012-01-12T03:43:40.500 に答える
2

うーん。あなたはC++が思いとどまらせるすべてのことをしているので、誰もがgotoを忘れていると思います。

明示的なX.~T()呼び出しの後、 1gotoが再構築される前に、変数xの宣言/初期化の前に(内部スコープブロック内であっても)誰かがtoを実行すると、二重の破棄が発生することに注意してください。

明らかにそれを文書化することができるので、これを「修正」しようとする面倒なことはしません。概念的には、オブジェクトの再構築をインプレースで管理するRAIIクラスを設計して、この操作をどこにいてもgotoに対して安全にすることができます。配置の新しいコンストラクター呼び出しをRAIIマネージャーオブジェクトのデストラクタから完全に転送することができることに注意してください。人生は素晴らしい。

もちろん、他の警告は引き続き適用されます(他の回答を参照)


1今のところノースロー建設を想定することができます

于 2012-01-12T07:59:09.910 に答える
0

これをやめることは何もありません、それはほとんどの場合うまくいくでしょう。しかし、多くのC ++の場合と同様に、ケースの詳細を知っていると、希望どおりに機能することとコアダンプの違いになります。実際のプログラムでこれを実行したい理由を私が理解できる理由の例はほとんどありません。意味のあるのはメモリマップトファイルだけです。

于 2012-01-12T10:05:07.977 に答える