2013-04-13 14 views
5

以下のサンプルコードでは、オブジェクトが2回コピーされるのはなぜですか?スレッドクラスのドキュメントコンストラクタによれば、すべての引数をスレッドローカルストレージにコピーするので、最初のコピーの理由があります。秒はどう?上記からstd :: threadなぜオブジェクトが2回コピーされるのですか?

class A { 
public: 
    A() {cout << "[C]" << endl;} 
    ~A() {cout << "[~D]" << endl;} 
    A(A const& src) {cout << "[COPY]" << endl;} 
    A& operator=(A const& src) {cout << "[=}" << endl; return *this;} 

    void operator()() {cout << "#" << endl;} 
}; 

void foo() 
{ 
    A a; 
    thread t{a}; 
    t.join(); 
} 

出力:

[C] 
[COPY] 
[COPY] 
[~D] 
# 
[~D] 
[~D] 

編集: まあはい、移動のコンストラクタを追加した後:

A(A && src) {cout << "[MOVE]" << endl;} 

出力は次のようなものです:

[C] 
[COPY] 
[MOVE] 
[~D] 
# 
[~D] 
[~D] 
+2

ちょっとした修正:引数は**スレッドローカル**ストレージにコピーされず、新しいスレッドのスタックにコピーされます。スレッドローカルストレージはまったく別の動物です。スレッドローカル変数は、本質的に、スレッド内の任意の関数からアクセス可能なスレッド単位のグローバル変数であり、各スレッド内に個別のコピーがあります。 –

+0

実際、2番目の[COPY]は '[MOVE]'ですが、移動コンストラクタが実装されていないため表示できません。 – soon

+0

上記の場合、2番目の[COPY]はコピーです。移動コンストラクタを提供するか、または= defaultを指定して明示的に宣言した場合にのみ、移動が行われます。 – Klaus

答えて

3

移動したい、またはコピーしたくないものは、コンストラクタを移動し、std::moveを使用することをお勧めします。

なぜ、これは自動的に私にとって起こりませんか?

C++での移動は保守的です。 std::move()を明示的に書くと、通常は移動します。これは、移動セマンティクスが非常に明示的な状況を超えて拡張されると、古いコードを破壊する可能性があるために行われました。自動移動は、しばしば、このような状況のために非常に慎重な状況に制限されます。

このような状況でコピーを避けるには、を入力してください(std::threadに渡しても)std::move(a)を使用して、aを移動する必要があります。最初にコピーを作成するのは、std :: threadがstd :: threadの作成を完了した後に値が存在することを保証できないため(明示的に移動していないため)、std :: threadが保証することができないためです。したがって、安全なことを行い、コピーを作成します(あなたが渡したものを参照してポインタを格納するのではなく、コードは生きているかどうかは分かりません)。

移動コンストラクタとstd::moveの両方を使用すると、コンパイラは構造を最大かつ効率的に移動できます。 VC++(CTPを使用するかどうか)を使用している場合は、明示的に移動コンストラクタを記述する必要があります。それ以外の場合は、MSVCがコピーコンストラクタを宣言して使用することがあります。

0

試してみますwith:スレッドt {std :: m ove(a)};

関連する問題