2

二重チェック ロックのこの修正の何が問題なのですか?へのコメント 言います:

問題は、オブジェクトが割り当てられる前ではなく、コンストラクターが実行される (または完了する) 前に変数が割り当てられる可能性があることです。

コードを考えてみましょう:

A *a;

void Test()
{
    a = new A;
}

より正式な分析を可能にするために、 a = new A をいくつかの操作に分割しましょう。

void *mem = malloc(sizeof(A)); // Allocation
new(mem) A; // Constructor
a = reinterpret_cast<A *>(mem); // Assignment

上記のコメントは本当ですか? もしそうなら、どのような意味ですか? 代入後にコンストラクタを実行できますか? 可能であれば、MT の安全性のために保証された順序が必要な場合、それに対して何ができるでしょうか?

4

4 に答える 4

1

問題はコードの実行時ではなく、書き込み順序に関係しています。

仮定しましょう:

A()
{
   member = 7;
}

じゃあ後で:

singleton = new A()

これにより、割り当て、メモリへの書き込み (メンバー)、および別のメモリ位置への書き込み (シングルトン) を行うコードが生成されます。一部の CPU は書き込みを並べ替えて、メンバーへの書き込みがシングルトンへの書き込み後まで表示されないようにすることができます。本質的に、システム内の他の CPU で実行されているコードは、シングルトンが書き込まれるメモリのビューを持つことができますが、メンバーはいいえ。

于 2009-06-17T22:06:28.350 に答える
1

私は次のように動作するはずだと思います:

void Test()
{
    A *temp = new A;
    MemoryWriteBarrier(); // use whatever memory barrier your platform offers
    a = temp;
}
于 2009-06-17T22:07:06.163 に答える
1

a静的ストレージ期間を持つグローバル オブジェクトであるため、メインの本体が実行される前に、事前に割り当てられたストレージで初期化されます。Test の呼び出しが静的オブジェクト構築の奇妙さの結果ではないと仮定すると、Test が呼び出されるまでaに完全に構​​築されます。

a = new A;

Aこの少し変わった代入は、オブジェクトや参照ではなく、へのポインターを代入しているため、標準のコピー代入操作 (のみ) にはなりません。それが実際にコンパイルされ、正確に何を呼び出すかAは、 へのポインターを取る代入演算子があるかどうかA、またはポインターから暗黙的に変換可能なものがあるAかどうか、またはポインター(またはベースへのAポインター) を取る非明示的なコンストラクターがあるかどうかによって異なります。AのクラスA)。

編集後、コードはかなり異なることを行います!

概念的には、次のようなことを行います。

A *tmpa;
void *mem = ::operator new( sizeof(A) ); // ( or possibly A::operator new )

try
{
    tmpa = new (mem) A; // placement new = default constructor call
}
catch (...)
{
    ::operator delete( mem );
    throw;
}

a = tmpa; // pointer assignment won't throw.

このようなものを書き出すことの危険は、オリジナルには存在しない多くのシーケンス ポイントを暗黙のうちに追加することです。さらに、コンパイラは、動作する限り、このように見えないコードを生成することができます。実行中のプログラムが判断できる限り、これによって書かれたかのように。(現在の) 言語は他のスレッドとの相互作用について何も述べていないため、この「あたかも」ルールは実行中のスレッドにのみ適用されます。

このためには、実装によって提供される特定の動作保証 (存在する場合) を使用する必要があります。

于 2009-06-17T21:55:45.547 に答える
-1

はい、コンストラクターは割り当て後に呼び出すことができますが、指定した例は内部的に一貫性がありません(コメントで示されています)。

あなたは安心のためにいくつかの錠を投げることができますが、それを間違えるのも簡単です。

見る

「C++とダブルチェックロックの危険性」

スコット・メイアーズとアンドレイ・アレキサンドレスク

http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

于 2009-06-17T22:04:50.053 に答える