13

(注:この質問は、この他の質問に答えるためのノーオペレーション割り当てを生成するためにプリプロセッサハッカーを考え出すことによって動機付けられました:

新しいオブジェクトを受け入れるマクロ

...それを覚えておいてください!)

考案されたクラスは次のとおりです。

class foo {
private:
    int bar;
public:
    foo(int bar) : bar (bar)
        { std::cout << "construct foo #" << bar << std::endl; }
    ~foo()
        { std::cout << "destruct foo #" << bar << std::endl; }
};

...これを次のように割り当てます:

// Note: for alignment, don't use char* buffer with new char[sizeof(foo)] !
void* buffer = operator new(sizeof(foo));

foo* p1 = new (buffer) foo(1);
foo* p2 = new (buffer) foo(2);

/* p1->~foo(); */ /* not necessary per spec and problematic in gen. case */
p2->~foo();

私が持っているgccで、「期待される」結果が得られます。

construct foo #1
construct foo #2
destruct foo #2

これは素晴らしいことですが、コンパイラ/ランタイムはこれを悪用として拒否し、それでも仕様の右側にある可能性がありますか?

糸脱毛はどうですか?このクラスの内容を実際に気にしない場合(とにかくダミーオブジェクトであるとしましょう)、POD intでこれを動機付けたさらに単純なアプリケーションのように、少なくともクラッシュすることはありませんか?

4

3 に答える 3

16

配置の実行-同じメモリブロックで数回新しいものを使用することはまったく問題ありません。さらに、奇妙に聞こえるかもしれませんが、そのメモリにすでに存在するオブジェクト(存在する場合)を破棄する必要はありません。標準では、3.8/4でそれを明示的に許可しています

4プログラムは、オブジェクトが占有するストレージを再利用するか、重要なデストラクタを持つクラスタイプのオブジェクトのデストラクタを明示的に呼び出すことにより、オブジェクトの存続期間を終了できます。自明でないデストラクタを持つクラスタイプのオブジェクトの場合、オブジェクトが占有するストレージが再利用または解放される前に、プログラムがデストラクタを明示的に呼び出す必要はありません。[...]

言い換えると、あるオブジェクトのデストラクタを呼び出さなかった場合の結果を考慮するのはあなたの責任です。

ただし、コードで行うのと同じオブジェクトでデストラクタを2回呼び出すことは許可されていません。同じメモリ領域に2番目のオブジェクトを作成すると、最初のオブジェクトの存続期間が事実上終了します(デストラクタを呼び出したことがない場合でも)。これで、2番目のオブジェクトを破棄するだけで済みます。

于 2011-09-23T04:52:46.263 に答える
3
foo* p1 = new (buffer) foo(1);
foo* p2 = new (buffer) foo(2);
p1->~foo();
p2->~foo();

同じオブジェクトを2回破壊していますが、それだけでは未定義の動作です。あなたの実装はあなたがそれをするときにピザを注文することを決定するかもしれません、そしてそれはまだスペックの右側にあります。

次に、foo型のオブジェクトを配置するためにバッファが適切に調整されていない可能性があるという事実があります。これも非標準のC ++です(C ++ 03によると、C ++ 11はこれを緩和すると思います)。

更新: タイトルで指定された質問について、

同じアドレスで複数回配置することは明確に定義されていますか/合法ですか?

はい、それは配置に明確に定義されていますか?それが生のメモリを指しているという条件で、同じアドレスで複数回新しくなります。

于 2011-09-23T04:36:33.177 に答える
0

いいえ-これは正しくありません。

配置を使用するnewと、オブジェクトは渡したアドレスに作成されます。この例では、同じアドレス(つまり、&buffer [0])を2回渡しているため、2番目のオブジェクトは、この場所に既に構築されている最初のオブジェクトを消去しているだけです。

編集:私はあなたがやろうとしていることを理解していないと思います。

一般的なオブジェクトタイプ(リソースを割り当て/割り当て解除する可能性のある重要なctor / dtorがある場合があります)があり、最初newにデストラクタを明示的に呼び出さずに最初のオブジェクトをその上に配置することで、最初のオブジェクトを消去します。メモリリークになります。

于 2011-09-23T04:41:47.333 に答える