トップページ – Modern C++編 C++編](../../index.html) – 第13章
問題① 次のプログラムのコメント部分では何が行われているかを、コンストラクタ、コピーコンストラクタ、コピー代入演算子、デストラクタといった関数のどれが呼び出されているのかという観点から説明してください。
class MyClass {
};
(MyClass mc)
MyClass func1{
return mc;
}
* func2(MyClass* mc)
MyClass{
return mc;
}
& func3(MyClass& mc)
MyClass{
return mc;
}
int main()
{
; // A
MyClass a= a; // B
MyClass b (b); // C
MyClass c* d; // D
MyClass
= a; // E
c
= func1(a); // F
c = func2(&a); // G
d = func3(a); // H
c }
Aは、実引数がありませんから、デフォルトコンストラクタが呼び出されます。MyClass には明示的なコンストラクタを定義していないので、コンパイラが自動的に生成したデフォルトコンストラクタが使用されます。
Bは、b と同じ型の a を初期値として与えていますから、コピーコンストラクタが呼び出されます。MyClass には明示的なコンストラクタを定義していないので、コンパイラが自動的に生成したコピーコンストラクタが使用されます。もし、コピーコンストラクタを明示的に定義しており、explicit が付いていたら、この記法はコンパイルエラーになります。
Cもコピーコンストラクタが呼び出されます。こちらは、explicit の付いたコピーコンストラクタを定義していても使用可能な構文です。
Dは、ポインタ変数の宣言なので、MyClass型のオブジェクトが作られるわけではありません。したがって、MyClass のコンストラクタが呼び出されることはありません。単に未初期化で、どこも指していないポインタ変数が定義されるだけです。
Eは、c も a も、MyClass型なので、「MyClass::operator=(const MyClass&)」のコピー代入演算子が使用されます。これは、明示的に定義していませんが、コンパイラが自動的に生成したものが使用されます。
Fは、まず引数 mc を作るために、a を使ったコピーコンストラクタが呼び出されます。戻り値も MyClass型なので、一時オブジェクトを作るために、mc を使ったコピーコンストラクタ(C++11以降ではムーブコンストラクタ)が呼び出されます。これを func1関数の呼び出し元が c に受け取ります。これは生成ではなく、代入なので、コピー代入演算子が呼び出されます。
また、この過程の中で、mc と一時オブジェクトを破棄するためのデストラクタが呼び出されます。
ただし、これらは理屈上の話で、実際には最適化によっていくつかの呼び出しは取り除かれるはずです。
Gは、func2関数の仮引数 mc は MyClass*型なので、単なるポインタ変数のやり取りです。戻り値も同様で、ポインタ変数を返すだけですから、MyClass のメンバ関数が呼び出されることはありません。
Hは、func3関数の仮引数 mc は参照なので、オブジェクトが作られることは無く、MyClass のメンバ関数が呼び出されることはありません。戻り値についても参照で返されているので、一時オブジェクトが生成されることはありませんが、受け取り側は実体の変数 c に代入しているため、コピー代入演算子は呼び出されます。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
![]() |
管理者情報 | プライバシーポリシー |