C++拷貝構造、賦值構造詳解
阿新 • • 發佈:2019-02-16
一、前言
寫一個用到指標的程式時,被拷貝、賦值、解構函式坑了一波,網上查相關部落格,發現關於拷貝、賦值建構函式呼叫時機大多都有錯誤,因此決定自己總結擼一發部落格。
A (A& a); //拷貝建構函式
A (const A& a); //拷貝建構函式
A& operator= (const A& a); //賦值建構函式
先寫一個類,用作之後的示例
class A {
public:
int* x;
int y;
A() = default;
A (const A& a) {
printf ("拷貝構造\n");
this->x = a.x;
this->y = a.y;
}
A& operator= (const A& a) {
printf ("賦值構造\n");
this->x = a.x;
this->y = a.y;
}
A (int t) {
x = new int (0);
y = t;
printf ("address: %x, point: %x, value: %d\n" , this, x, y);
}
~A() {
printf ("delete %x\n", this);
}
};
A f () {
A ret (3);
printf ("stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);
return ret;
}
二、不會呼叫拷貝建構函式和賦值建構函式的情況
1.當物件以值傳遞的方式從函式返回,且接受返回值的物件是由該返回值初始化時,不會呼叫任何建構函式。(相當於把該物件重新命名為另一個物件名)
int main() {
A c = f(); //此時不呼叫任何建構函式
printf ("global address: %x ,value: %d\n", &c, c.y);
return 0;
}
三、拷貝建構函式
1.物件需要通過另外一個物件進行初始化
int main() {
A a(1);
A c = a;
printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
return 0;
}
2.物件通過值傳遞方式進入函式
void g (A ret) {
printf ("stack address: %x, point: %x, value: %d\n", &ret, ret.x, ret.y);
}
int main() {
A a (1);
g (a);
return 0;
}
四、賦值建構函式
1.物件以值傳遞方式從函式返回,且接受返回值的物件已經初始化過
int main() {
A c;
c = f();
printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
return 0;
}
2.物件直接賦值給另一個物件,且接受值的物件已經初始化過
int main() {
A a(1);
A c;
c = a;
printf ("global address: %x, point: %x, value: %d\n", &c, c.x, c.y);
return 0;
}
五、總結
物件以值傳遞方式從函式返回時,若接受返回值的物件已經初始化過,則會呼叫賦值建構函式,且該物件還會呼叫解構函式,當物件中包含指標時,會使該指標失效,因此需要過載賦值建構函式,使用類似深拷貝或移動建構函式的方法賦值,才能避免指標失效。
物件以值傳遞方式從函式返回時,若接受返回值的物件是由該返回值初始化,則不會呼叫任何建構函式,且不會呼叫解構函式。