web-dev-qa-db-ja.com

オブジェクトを値による引数としてメソッドに渡すときに、コピーコンストラクターが呼び出されるのはなぜですか?

オブジェクトを値による引数として関数に渡すときに、コピーコンストラクターが呼び出されるのはなぜですか?以下のコードを参照してください。クラスのオブジェクトを値による引数として関数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;
}
16

すでに少し与えられた2つの答えを詳しく説明するには:

変数を他の変数と「同じ」と定義する場合、基本的に2つの可能性があります。

ClassA aCopy = someOtherA; //copy
ClassA& aRef = someOtherA; //reference

非const左辺値参照の代わりに、もちろんconst参照と右辺値参照があります。ここで指摘したい主なことは、aCopysomeOtherAから独立しているのに対し、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&で読み取り専用パラメーターを渡すことをお勧めします。

19
Arne Mertz

関数に値を渡すということは、関数がオブジェクトの独自のコピーを持っていることを意味するからです。この目的のために、コピーコンストラクターが呼び出されます。

void display(ClassA obj)
{
   // display has its own ClassA object, a copy of the input
   cout << "Hello World" << endl;
}

たとえば、一時的な値が関数に渡された場合など、コピーが省略される場合があることに注意してください。

6
juanchopanza

Juanchopanzaが言ったように:、あなたは値を渡すので、コピーが作成されます。これを防ぎたい場合は、参照して渡すことができます。

void display(const ClassA &obj)

補足:引数をconst参照として使用するには、コピーctorを宣言する必要があります。

ClassA(const ClassA &obj)

そうしないと、constまたはtemporariesとしてマークされた名前付きオブジェクトでcopyctorを使用できなくなります。また、渡されたオブジェクトを誤って変更することも防ぎます。

4
Tom