127-C ++で5番目の箇条書きを学習

コンストラクターの特性:自動的に転送され、コンストラクターをアクティブに転送することはできません。
コンストラクターは整数データを使用してオブジェクトを初期化します。つまり、組み込み型の
コピーコンストラクターは1つのオブジェクトを使用して別のオブジェクトスペースを初期化します。実際のパラメーターオブジェクトと正式なパラメーターオブジェクトを組み合わせると、2.returnはオブジェクトを返します。

Int fun(Int x)
{
    
    
	int a=x.Value();
	Int tmp(a);
	return tmp;
}

int main()
{
    
    
	Int a(10);
	Int b;
	b=fun(a);

	return 0:
}

実際のパラメータオブジェクトであり、仮パラメータオブジェクトを初期化すると、コピーコンストラクタが呼び出されます。tmpを返すとき、一時オブジェクトを返したい場合は、コピーコンストラクタを呼び出して、戻りとして一時オブジェクトを作成する必要があります。tmpをbオブジェクトに直接指定することはできないため、tmpをbオブジェクトに直接指定すると、両方の関数でtmpが存続します。これは、ローカルオブジェクトが関数で有効になるのは、関数がここには、死の値という概念があります。tmpに戻ると、メイン関数のスタックフレームに一時オブジェクトを作成します。一時オブジェクトがbに割り当てられると、一時オブジェクトの有効期間が到来します。このオブジェクトをデッド値と呼びます。

デストラクタの機能:オブジェクトを解放し、オブジェクトが含まれているリソースを解放します。
デフォルトの機能:コンストラクタを記述しない場合、システムはデフォルトのコンストラクタを提供します(オブジェクトを作成するだけで、オブジェクト自体を初期化することはできません。データはランダムな値)、コピーコンストラクタ(オブジェクトのアドレスを取得し、構築するオブジェクトのアドレスを取得して、ビットごとにコピーします)

Int& operator=(const Int& it)
{
    
    
}//a=b

デフォルトのコンストラクタ:bのアドレスを取得し、aのアドレスを取得し、bの内容をバイトごとにbにコピーし、ビットごとにコピーします

デフォルトのコピーコンストラクターが要件を満たしている場合と、要件を満たしていない場合があります。リソースを申請しない場合は、要件を満たすことができます。リソースを申請する場合は、要件を満たすことができません。 。

Int& operator=(const Int& it)
	{
    
    
		if (this != &it)//防止自己给自己赋值,a=a
		{
    
    
		value = it.value;
		}
		cout << this << " = " << &it << endl;
	return *this;
}//a=b

ここでの代入ステートメントは型への参照を返しますが、なぜここで独自の型への参照を返すのですか?a = b;はこのポインタを返し、このポインタはaを指します。*これはオブジェクト自体であり、それ自体を参照として返します。関数が終了すると、このポインタも終了し、これが指すオブジェクトはそうではありません。この関数の影響を受ける影響、この関数が終了しても、オブジェクトはまだ存在しているため、参照によって返すことができます。演算子のオーバーロード。オーバーロードされた演算子の能力が、組み込み型の能力に近いことを願っています。a = b = cを実現するために、継続的な割り当ての能力。a = operator =(&b、c); bは代入ステートメントを動員し、bのアドレスをそれに渡します。メンバー関数として、これを含み、cを使用して初期化します。これは、cのエイリアスであり、これはアドレスを指します。 bの、*これを返します。これはbオブジェクトであり、bオブジェクトをaに割り当てます。

Int a(a); aの構築が完了していないため、コンパイラーはコンパイル時にエラーを出します。どうすれば自分で構築できますか?

void SetValue(int x) {
    
     value = x; }
int GetValue() const {
    
     return value; }

int& Value() {
    
     return value; }

int&Value(){戻り値;}は値を取り、値を割り当てることができます

int main()
{
    
    
	Int a(10);
	Int x=a.Value();
	a.Value()=100;//把100赋值给Value()的返回值,这个返回值Value对象也就是a的别名 被系统解释成a.value=100;
	return 0;
}

通常のオブジェクトの場合は、それを呼び出すことができます
。constInta(10);が定数オブジェクトになると、aのプロパティ値を変更できないことを意味します。通常の参照によって値が返されるときに、値を変更できます。 、矛盾、および文法上のあいまいさをもたらします。
このような機能は一般的にペアで表示されます

const int& Value() {
    
     return value; }
const Int a(10); 

共通オブジェクトが共通オブジェクトメソッドを
呼び出す共通オブジェクトが共通メソッドを呼び出す

int funa()
{
    
    
	int tmp = 10;
	return tmp;
}
int main()
{
    
    
	int x=0;
	x=funa();
	cout<<x<<endl;
	return 0;
}

funa()は整数変数を作成し、tmpを返し、遷移として一時変数を作成します。
プログラムの実行が開始されると、main関数が実行されます。コンパイラは、それが組み込み型であることを検出し、スタックフレームを割り当てます。 x変数、funaを動員し、funaにスタックフレームを割り当て、tmp = 10を定義し、tmpを返します。tmp10の値をeaxに入れてから、funaのtmpを返します。これは、終了したことを意味します。割り当てられたスタックフレームが終了しました。メイン関数に戻るときに、レジスタeaxで取得した値をxに指定します。
ここに画像の説明を挿入

int&x = funa();を受け取るための参照に問題がある場合、その参照はエイリアスと同等です。システムがコンパイルされると、参照はポインターにコンパイルされます。funaを動員するときに、tmp = 10; returnを定義します。 tmp; weレジスタeaxには、tmpの整数値が配置されます。この参照は、eaxまたはこの10を指すことを考えて、許可されていません。デッドバリューの概念(アドレスを取得できません)

 const int &x=funa();  

上記の方法は可能であり、普遍的な参照です。eaxに返される値は、 int tmp = eax; const int&x = tmp;
を実行するの同じですが、ここにメイン関数のメモリスペースがあります。


以下の方法も可能です!右辺値参照

int&& x = funa();
// int tmp = eax;
// int &&x = tmp;

この死亡値の寿命はxと同じになります

次のコードは非常に重要です

int& fun()
{
    
    
	int x = 10;
	return x;
}

int main()
{
    
    
	int a=fun();
	int&b=fun();
	cout<<a<<endl;//打印出10
	cout<<b<<endl;//打印出随机值
	return 0;
}

しかし、このコードは間違っています!
存続期間の問題
参照によって値を返したい場合、このデータまたはこの変数またはこのオブジェクトの存続期間は、fun関数によって制限されません。つまり、参照によって返されるとき、fun関数が終了するときxこの変数の有効期間は満了しておらず、xはまだ存続しています。変数をそのアドレスに返したり、参照を返したりする場合、変数の有効期間はこの関数の影響を受けません。
この例では、xが返され、xの有効期間はfun関数fun()の影響を受けます。それが終わると、xの寿命は終わります。プログラムの実行中は、メイン関数が実行され、スタックフレームをメイン関数に割り当て、変数aを定義します。このとき、aには値がありません。fun()を呼び出し、fun用のスペースを割り当て、x = 10を定義します。 xを参照に戻すReturn、参照の本質はシステムによってアドレスとして解釈され、eaxはxのアドレスを格納し、xを返します。終了すると、funに割り当てられたスタックフレームが破棄され、eaxはこのスペースを指します。このスペースは期限切れですが、aは整数変数です。eaxを格納することはできません。このステップは体系的に説明されています:a = * eax;ここに質問があります:このスペースは侵入から保護されていますか?邪魔されていない場合は10を読み取ることができます。邪魔されている場合は10を読み取ることはできません。ここで、bは参照、実際にはbはポインターであり、返されるのは参照、xのアドレスです。 bはxのアドレスを指します。aを印刷する場合はaの値が取得されています。bを印刷する場合はポイントして印刷されます。cout自体は出力関数です(スタックフレームを開いて、のスペースをカバーします)。このメモリ領域に侵入するため、ランダムな値が出力されます。
シングルスレッドの割り当ては妨げられません。
マルチスレッドの割り当ては、特定のエラーによって中断される場合があり
ここに画像の説明を挿入
ます。印刷時に、10がaにコピーされ、侵入しました。aはすでに10であり、bはこの値をコピーしていません。

Int fun()
{
    
    
	Int a(10);
	return a;
}
int main()
{
    
    
	Int x=fun();//OK
}

fun();を動員してオブジェクトaを生成し、それが戻ると、一時オブジェクトaが生成され、関数funが終了し、オブジェクトが終了し、一時オブジェクトaがコピーされてxが作成されます。

Int &x=fun();//error

エラーの理由:一時オブジェクトaは無効な値であり、無効な値を参照できません。
関数が終了すると、一時オブジェクトは破棄され、文法規則では許可されません。

const Int &x=fun();//ok

定数参照、それが構築したオブジェクトを参照します。これはこのメイン関数の一時オブジェクトを参照します。これは変更できません。

Int&&x=fun();//ok

右辺参照引用は値を終了します。
ここに画像の説明を挿入
ここに画像の説明を挿入
システムにはデフォルトの代入ステートメントがあります。
ここに画像の説明を挿入
値を代入する場合、システムのデフォルトの代入ステートメントは、aとbのアドレスを取得し、aの値をコピーして、10を出力しますが、間違っています。
なぜなら、aが作成されると、代入ステートメントが呼び出されると、元の楽しいスペースが再びシャッフルされ、aの値が上書きされるからです。
ここに画像の説明を挿入
印刷されるのはまだランダムな値であり、
返されたオブジェクト参照は停止しています

class String
{
    
    
	char* str;
public:
	String(const char* s = nullptr)
	{
    
    
		if (s != nullptr)
		{
    
    
			int len = strlen(s);
			str = new char[len + 1];
			strcpy_s(str, len + 1, s);
		}
		else
		{
    
    
			str = new char[1];
			*str = '\0';
		}
	}

	~String()
	{
    
    
		if (str != nullptr)
		{
    
    
			delete[]str;
		}
		str = nullptr;
	}
};

システムのデフォルトのデフォルトのコピーコンストラクタ
ここに画像の説明を挿入

String(const String& st)//浅拷贝
	{
    
    
		str = st.str;
	}

ディープコピー
ここに画像の説明を挿入

String(const String& st)//深拷贝
	{
    
    
		int len = strlen(st.str);
		str = new char[len + 1];
		strcpy_s(str, len + 1, st.str);
	}

ここに画像の説明を挿入
s1をs2に割り当てる場合、デフォルトの割り当て関数は、s1のstr値をs2のstrに割り当て、s2のstrが直接ポイントされるようにします。これの何が問題になっていますか?
1.メモリリーク2.s2オブジェクトが破壊されると、プログラムがクラッシュし、2回解放されます

	String& operator=(const String& st)
	{
    
    
		str = st.str;
		return *this;//按位赋值,缺省构造
	}

自分で作成した割り当て関数

String& operator=(const String& st)
	{
    
    
		if (this != &st)
		{
    
    
			delete[]str;
			int len = strlen(st.str);
			str = new char[len + 1];
			strcpy_s(str, len + 1, st.str);
		}
		return *this;
	}

ここに画像の説明を挿入

main関数は、s1(構築されていない)とstrのランダムな値を割り当てます。fun()を呼び出すときは、スタックフレームs、strを割り当て、ヒープ領域からスペースを割り当て、yhpinghelloをコピーして、通常どおり返します。 Press値が返され、一時オブジェクトが作成され、コピーコンストラクタが呼び出され、一時オブジェクトstrもヒープスペースyhpinghelloを指します。一時オブジェクトが作成されると、関数は終了し、sの有効期間が終了します。 。デストラクタを呼び出してスペースを解放し、ヒープが存在しない場合、メイン関数に戻るときに、この一時オブジェクトはs1を構築し、スペースを開き、yhpinghelloをコピーする必要があります。その後、一時オブジェクトの有効期間が終了し、デストラクタが解放されます。このメソッドは複数のオブジェクトを作成するため、非効率的です。
ここに画像の説明を挿入

モバイル構造

システムのモバイル構造

	String(String&& s)
	{
    
    
		str = s.str;
		//delete[]s.str;
		s.str = nullptr;
	}

sを返すと、デッド値が返されます。システムは、sをString(String && s)のsに初期化し、移動構造を動員し
ここに画像の説明を挿入
、リソースを移動してsオブジェクトのリソースをs1に転送しs.strを空
設定します。ローカルオブジェクトを作成する
ここに画像の説明を挿入
2つの書き込み方法は異なり
ます。最初の書き込み方法は、返されたオブジェクトを取得してs1を構築し、モバイル構造をモバイル化し、sのリソースをs1に提供します
。2番目のメソッドはモバイル構造をモバイル化しません。コンストラクターはオブジェクトを作成することです。コピーコンストラクターもオブジェクトを作成することです。移動構造体もオブジェクトを作成することですが、s2オブジェクトは既に存在するため、割り当て関数を移動します。

String& operator=(String&& s)
	{
    
    
		if (this != &s)
		{
    
    
			delete[]str;
			str = s.str;
			s.str = nullptr;
		}
		return *this;
	}

元のメソッド
ここに画像の説明を挿入
が移動構造を持っている場合、それは便利で
ここに画像の説明を挿入
同等です

return s;ムーブ構文を使用して一時オブジェクトを構築します。一時オブジェクトのstrポインタはsオブジェクトのyhpinghelloを指し、sのstrはnullに設定されます。関数が構築されると、sオブジェクトは破棄されます。そして、yphinghelloによって解放されません。メイン関数に戻ります。デッド値をムーブ代入ステートメントに転送します。この時点で、sはムーブ代入のエイリアスです。
ここに画像の説明を挿入
このメソッドの新しいスペースは1回だけ新しいです。
戻り値sは直接構築されたs1(モバイル構築)
ここに画像の説明を挿入

モバイルコンストラクタ、モバイル代入関数システムがありますが、使用したい場合は自分で実装する必要があります

おすすめ

転載: blog.csdn.net/LINZEYU666/article/details/112111388