質問
最近、そうするコードを書きました
SomeClass someObject;
mysqlpp::StoreQueryResult result = someObject.getResult();
SomeClass :: getResult()は次のようになります:
mysqlpp::StoreQueryResult SomeClass::getResult()
{
mysqlpp::StoreQueryResult res = ...<something>...;
return res;
}
最初のコードスニペットの例を使用して、コンパイルして実行すると、プログラムはABORTシグナルでクラッシュしました。次に、最初のスニペットを次のように変更しました。
SomeClass someObject;
mysqlpp::StoreQueryResult result(someObject.getResult());
これはうまくいきました。また、試してみるために、もう一度次のように変更しました。
SomeClass someObject;
mysqlpp::StoreQueryResult result;
result = someObject.getResult();
これも正常に機能しました。
今、最初の例が失敗し、次の2つが成功した理由がわかりません。私が理解するように、最初の例では、結果を初期化するためにコピーコンストラクターが使用されます。しかし、これは2番目の例にも当てはまりませんか?では、なぜ2番目の例が成功したのでしょうか? 3番目の例はもう少し理にかなっています-copy constは使用されないので、構築後に割り当てるだけです。
要するに、次の違いは何ですか:
FooClass a = someObject.someMethodReturningFooClassInstance();
and
FooClass a(someObject.someMethodReturningFooClassInstance());?
Muchosありがとう!
解決
2つのケースに違いはないと思います。同じコピーコンストラクターが両方とも呼び出されます。
これは、コードで書いたものと正確に確かですか?
他のヒント
厳密に言えば、最初のケースではデフォルトのコンストラクターが呼び出され、その後に代入演算子が続き、2番目のケースではコピーコンストラクターのみが使用されます。
さて、私の最初の仮定は間違っていて、明らかにどちらの場合でもコピーコンストラクターだけが呼び出されます(割り当ての場合は、追加の「変換」コンストラクターも呼び出されます)。しばらくスリープした後にコンパイラを起動し、開発環境でこれを確認します。
コピーコンストラクター内にブレークポイント(またはprintfステートメント)を入れるだけで、いつ呼び出されたかを正確に知ることができます。基本的なデバッグを置き換えることはできません。 ;)
しかし、はい、コピーコンストラクターは最初の2つの場合に呼び出す必要があります。 3番目のケースでは、代わりに代入演算子を使用します。
デバッガで実行してみましたか? ABORTシグナルで中断します。
まあ、最初のものはoperator =で中間コピーを行い、2番目のものは直接コピー構成を行います。
最初のケースはオブジェクトに値(正しい値)が割り当てられていると思います。オブジェクトに値を送信します。2,3では、暗黙的なオブジェクトと明示的なオブジェクトの概念があります。 p>
最も純粋な理論では、どちらの場合でもコピーコンストラクターを呼び出す必要があります。 ただし、これらの場合にコンパイラーが使用できるReturn Value Optimization(RVO)と呼ばれるものがあります。 RVOを使用する場合、コピーコンストラクターは呼び出されません。おそらく、コンパイラーはRVOを1つのケースで使用し、他のケースでは使用しませんか?
編集: これはケースにのみ適用されます
SomeClass someObject;
mysqlpp::StoreQueryResult result;
result = someObject.getResult();