コンストラクターの特性:自動的に転送され、コンストラクターをアクティブに転送することはできません。
コンストラクターは整数データを使用してオブジェクトを初期化します。つまり、組み込み型の
コピーコンストラクターは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(モバイル構築)
モバイルコンストラクタ、モバイル代入関数システムがありますが、使用したい場合は自分で実装する必要があります