オブジェクトを値による引数として関数に渡すときに、コピーコンストラクターが呼び出されるのはなぜですか?以下のコードを参照してください。クラスのオブジェクトを値による引数として関数display()
に渡していますが、コントロールがdisplay()
関数にヒットする前にコピーコンストラクターを呼び出しています。 。理由がわかりません。
#include "stdafx.h"
#include <iostream>
using namespace std;
class ClassA
{
private:
int a, b;
public:
ClassA()
{
a = 10, b = 20;
}
ClassA(ClassA &obj)
{
cout << "copy constructor called" << endl;
a = obj.a;
b = obj.b;
}
};
void display(ClassA obj)
{
cout << "Hello World" << endl;
}
int main()
{
ClassA obj;
display(obj);
return 0;
}
すでに少し与えられた2つの答えを詳しく説明するには:
変数を他の変数と「同じ」と定義する場合、基本的に2つの可能性があります。
ClassA aCopy = someOtherA; //copy
ClassA& aRef = someOtherA; //reference
非const左辺値参照の代わりに、もちろんconst参照と右辺値参照があります。ここで指摘したい主なことは、aCopy
はsomeOtherA
から独立しているのに対し、aRef
は実質的にsomeOtherA
と同じ変数であるということです。別の名前(エイリアス)。
関数パラメーターでは、基本的に同じです。パラメータが参照の場合、関数が呼び出されたときに引数にバインドされ、その引数の単なるエイリアスになります。つまり、パラメーターを使用して行うことは、引数を使用して行うことです。
void f(int& iRef) {
++iRef;
}
int main() {
int i = 5;
f(i); //i becomes 6, because iRef IS i
}
パラメータが値の場合、それは引数のコピーにすぎないため、パラメータに何を行っても、引数は変更されません。
void f(int iCopy) {
++iCopy;
}
int main() {
int i = 5;
f(i); //i remains 5, because iCopy IS NOT i
}
値を渡すと、パラメーターは新しいオブジェクトになります。それは議論と同じではないので、それは独立している必要があります。引数のコピーである新しいオブジェクトを作成するということは、引数が左辺値か右辺値かに応じて、コピーコンストラクターまたは移動コンストラクターを呼び出すことを意味します。あなたの場合、引数を読むだけなので、関数に値を渡す必要はありません。
ガイドライン GotW#4 :があります
読み取り専用パラメーター(コピーを作成しない)から読み取る場合は、const&で読み取り専用パラメーターを渡すことをお勧めします。
関数に値を渡すということは、関数がオブジェクトの独自のコピーを持っていることを意味するからです。この目的のために、コピーコンストラクターが呼び出されます。
void display(ClassA obj)
{
// display has its own ClassA object, a copy of the input
cout << "Hello World" << endl;
}
たとえば、一時的な値が関数に渡された場合など、コピーが省略される場合があることに注意してください。
Juanchopanzaが言ったように:、あなたは値を渡すので、コピーが作成されます。これを防ぎたい場合は、参照して渡すことができます。
void display(const ClassA &obj)
補足:引数をconst参照として使用するには、コピーctorを宣言する必要があります。
ClassA(const ClassA &obj)
そうしないと、constまたはtemporariesとしてマークされた名前付きオブジェクトでcopyctorを使用できなくなります。また、渡されたオブジェクトを誤って変更することも防ぎます。