[C++]Chapter 05-レプリケーションジェネレータ


05-1コピー作成者との初対面


C++スタイルの初期化


C++で変数と参照者を初期化する方法は次のとおりです.
int num = 20;
int &ref = num;

int num(20);
int &ref(num);
オブジェクトの作成に移動します.
SoSimple sim2 = sim1;
SoSimple sim2(sim1);
クラス内で次のシェイプと類似シェイプを受信するには
SoSimple(SoSimple & copy)
{
}
同じ作成者が必要です.ただし、クラスにこのような作成者がいなくても、レプリケーション作成者は自動的に挿入されます.

デフォルトのレプリケーション作成者(自動挿入)


レプリケーション作成者が定義されていない場合、メンバーからメンバーへのレプリケーションを行うレプリケーション作成者が自動的に挿入されます.
そして.
SoSimple sim2 = sim1; 
自動
SoSimple sim2(sim1);
これは「暗黙的」遷移と呼ばれる変化です.そのため、構造関数にexplicitを追加すると、「暗黙的」遷移は発生しません.
explicit SoSimple(const SoSimple &copy) : num(copy.num1), num2(copy.num2)
{
}
コピー作成者が参照宣言を表す&を挿入していない場合、コピー作成者の呼び出しは無限のループに陥ります.

05-2「深い放射線」と「浅い放射線」


レプリケーション作成者の問題点

#include <iostream>
#include <cstring>
using namespace std;

class Person
{
private:
	char* name;
	int age;
public:
	Person(const char* myname, int myage)
	{
		int len = strlen(myname) + 1;
		name = new char[len];
		strcpy(name, myname);
		age = myage;
	}
	void ShowPersonInfo() const
	{
		cout << "이름: " << name << endl;
		cout << "나이: " << age << endl;
	}
	~Person()
	{
		delete[]name;
		cout << "called destructor!" << endl;
	}
};

int main(void)
{
	Person man1("Lee dong woo", 29);
	Person man2 = man1;
	man1.ShowPersonInfo();
	man2.ShowPersonInfo();
	return 0;
}
これらのコードに問題があるのはPerson man 2=man 1が浅いコピーであり,単純なコピーであるためdeleteがman 1とman 2に適用された場合(man 2を先に削除すると仮定)、man 2はman 1を参照しているが,まずman 1の空間を削除しているため,man 1にdeleteを適用するとエラーが発生する.
コードを深くコピー
#include <iostream>
#include <cstring>
using namespace std;

class Person
{
private:
	char* name;
	int age;
public:
	Person(const char* myname, int myage)
	{
		int len = strlen(myname) + 1;
		name = new char[len];
		strcpy(name, myname);
		age = myage;
	}
	Person(const Person& person)
	{
		name = new char[strlen(person.name) + 1];
		strcpy(name, person.name);
		age = person.age;
	}
	void ShowPersonInfo() const
	{
		cout << "이름: " << name << endl;
		cout << "나이: " << age << endl;
	}
	~Person()
	{
		delete[]name;
		cout << "called destructor!" << endl;
	}
};

int main(void)
{
	Person man1("Lee dong woo", 29);
	Person man2 = man1;
	man1.ShowPersonInfo();
	man2.ShowPersonInfo();
	return 0;
}

05-3作成者のコールポイントのコピー


レプリケーション作成者には3つのコールポイントがあります
  • 既存作成オブジェクトを使用して新しいオブジェクトを作成する場合:
  • が値によって関数を呼び出す過程で、オブジェクトをパラメータとして渡す:
  • オブジェクトが返されますが、参照として返されない場合は
  • です.
    Case1
    int num1 = num2;
    Case2
    int SimpleFunc(int n)
    {
    	....
    }
    int main(void)
    {
        int num = 10;
        SimpleFunc(num); // 호출되는 순간 매개변수 n이 할당과 동시에 초기화
        ...
    }
    Case3
    int SimpleFunc(int n)
    {
    	...
        return n; // 반환하는 순간 메모리 공간이 할당되면서 동시에 초기화!
    }
    int main(void)
    {
        int num = 10;
        cout << SimpleFunc(num) << endl;
        ....
    }
    case 3に戻ると、一時変数とオブジェクトが作成されます.

    一時オブジェクト

    #include <iostream>
    using namespace std;
    
    class Temporary
    {
    private:
    	int num;
    public:
    	Temporary(int n) : num(n)
    	{
    		cout << "create obj: " << endl;
    	}
    	~Temporary()
    	{
    		cout << "destroy obj:" << endl;
    	}
    	void ShowTempInfo()
    	{
    		cout << "My num is " << num << endl;
    	}
    };
    
    int main(void)
    {
    	Temporary(100);
    	cout << "********* after make!" << endl << endl;
    
    	Temporary(200).ShowTempInfo();
    	cout << "********* after make!" << endl << endl;
    
    	const Temporary& ref = Temporary(300);
    	cout << "********* end of main!" << endl << endl;
    	return 0;
    }
    実行結果

    結果を説明する前に、オブジェクトのメンバー関数を呼び出すために必要な3つの項目は、次のとおりです.
  • オブジェクトの名前
  • オブジェクトの参照値
  • オブジェクトのアドレス値
  • 上のTemporay(200).ShowTempInfo(); 度(一時オブジェクトの参照値).ShowTempInfo()などの文の構成
    上に示す結果、一時オブジェクトは次の行に進むとすぐに消えますが、参照者が参照する一時オブジェクトはすぐに消えません.

    参照される一時オブジェクトの消失時間。

    #include <iostream>
    using namespace std;
    
    class SoSimple
    {
    private:
    	int num;
    public:
    	SoSimple(int n) : num(n)
    	{
    		cout << "New Object: " << this << endl;
    	}
    	SoSimple(const SoSimple& copy) : num(copy.num)
    	{
    		cout << "New Copy obj: " << this << endl;
    	}
    	~SoSimple()
    	{
    		cout << "Destroy obj:" << this << endl;
    	}
    };
    
    SoSimple SimpleFuncObj(SoSimple ob)
    {
    	cout << "Parm ADR: " << &ob << endl;
    	return ob;
    }
    
    int main(void)
    {
    	SoSimple obj(7);
    	SimpleFuncObj(obj);
    
    	cout << endl;
    	SoSimple tempRef = SimpleFuncObj(obj);
    	cout << "Return Obj" << &tempRef << endl;
    	return 0;
    }
    実行結果

    SoSimple obj(7)を実行するのは初めてです.オブジェクトはreturn 0(すなわち、関数が終了する前に作成され、消えます).したがってtemprefが参照するオブジェクトの消失はtemprefが関数を終了する時点である.
    ここで、temprefは他のオブジェクトを作成せず、一時オブジェクトに名前を割り当てるだけです(オブジェクトの作成数を減らすことで効率が向上します)-->temprefは一時オブジェクトのアドレス値と同じです.