4

私はC++で移動コンストラクタを理解することが困難でした。私は既定のコンストラクタ、コピーコンストラクタ、移動コンストラクタ、およびデストラクタを使用して簡単なクラスを作成しました。また、2つのオーバーロードを持つ関数を定義しました。そのクラスへの参照を受け取り、そのクラスへの参照値を受け入れます。私のテストコードは以下の通りです。移動コンストラクタとの混乱:移動コンストラクタを呼び出すことができません

#include <iostream> 


class c { 

public: 

    c() { 
     std::cout << "default constructor" << std::endl; 
    } 

    c(const c& s) { 
     std::cout << "copy constructor" << std::endl; 
    } 

    c(c&& s) { 
     std::cout << "move constructor" << std::endl; 
    } 

    ~c() { 
     std::cout << "destructor" << std::endl; 
    } 

}; 

void f(c& s) { 
    std::cout << "passed by reference" << std::endl; 
} 

void f(c&& s) { 
    std::cout << "passed by rvalue reference" << std::endl; 
} 

int main() { 

    c s1; // line 1 
    std::cout << "\n"; 
    c s2(s1); // line 2 
    std::cout << "\n"; 
    c s3(c()); // line 3 

    std::cout << "\n"; 

    f(s1); // line 4 
    std::cout << "\n"; 
    f(c()); // line 5 

    getchar(); 
    return 0; 

} 

出力は私が期待していたものではありません。以下は私がこのコードから得ている出力です。

default constructor 

copy constructor 

passed by reference 

default constructor 
passed by rvalue reference 
destructor 

line 3を除くすべての行の出力を理解できます。 であるline 3で、c()は値ですので、私はs3が構築されることを期待しています。しかし、アウトプットには、それが建設されたことが示されていない。 line 5で、私は同じことをしており、を関数f()に渡しています。実際にはrvalueの参照を受け付けるオーバーロードを呼び出します。私は非常に混乱しており、これに関する情報は感謝しています。

編集:c s3(std::move(c()));を実行すると移動コンストラクタを呼び出すことができますが、まだrvalueをs3に渡していませんか?なぜ私はstd::moveが必要でしょうか?

+2

は本当にこの1の複製ではありません。ここで起こっているのは、Elisationをコピーするのではなく、Most Vexing Parseです。 – Angew

+0

@Angew良いお電話。それを逃した。 – NathanOliver

+0

@Angew私が実際にやろうとしたのは、移動コンストラクタを使ってオブジェクトを構築することでした.NathanOliverが私を別の質問に導いたとき、私は本当にこれが重複していると考えました。あなたが指摘するまで、3行目のステートメントが関数シグネチャであることに気付かなかった。私は一度も煩わしさを聞いたことがないので、それを私と共有してくれてありがとう。私はそれが何であるかを知るためにそれを読んでいます。 – Deniz

答えて

9

3行目の出力が表示されない理由は、変数ではなく関数を宣言しているためです。これは、Most Vexing Parseというあいまいさが原因です。

c s3(c())int foo(int())を比較します。暗黙的な型調整のおかげで、int foo(int (*f)())と同じです。

は、この問題を回避するには、(実際には一部がまさにこの理由のためにC++ 11で導入された)使用ブレースの初期化:その@NathanOliver

c s3(c{}); 

// or 

c s3{c()}; 

// or 

c s3{c{}}; 
+0

有益な答えをありがとう。これとM.Mの答えは、私の質問に答えます。しかし、明らかにあなたは一分早く元気だったので、私はあなたの答えを受け入れるでしょう。 M.Mさん、ありがとうございました。 – Deniz

5

c s3(c());はオブジェクトを構成しません。これは関数宣言です。この関数はs3と呼ばれ、戻り値の型はcであり、パラメータ型は "パラメータを取らずに戻り値cを返す関数へのポインタ"です。したがって、関数宣言は関数を呼び出さないので、出力は得られません。

このようなことを避けるには、リストの初期化を使用することができます。c s3{c()};は、おそらくあなたが気にしていたものと一線を画しています。

+0

infoの 'parameter type for +1'は、パラメータを取らずにc "を返す関数へのポインタです。それが 'c(x)'ならば、パラメータ型は 'c'であり、名前は' x'です。 –

関連する問題