一、賦值構造函數是什麼
在C++中,如果我們定義一個類,它裡面包含有指針成員變量時,需要特別注意這個指針的生命周期和對象的生命周期,確保在對象被銷毀前,指針指向的內存已經被釋放,否則可能會發生內存泄漏等問題。而賦值構造函數就是用來實現對象的深度複製,解決因為指針成員變量導致的這類問題。
class Test{
public:
Test():data(nullptr), len(0) {}
~Test(){
if(data != nullptr)
delete[] data;
}
Test(const Test& t){
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
}
Test& operator=(const Test& t){
if(this == &t) return *this;
if(this->data != nullptr) delete[] data;
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
return *this;
}
private:
int* data;
int len;
};
二、淺拷貝和深拷貝的區別
在實現賦值構造函數之前,我們需要先了解一下淺拷貝和深拷貝的概念。
所謂淺拷貝,是將對象的所有成員變量的值都複製給新對象,包括指針成員變量的地址值,也就是說,新對象和原對象共享指針指向的內存。這樣,當其中一個對象釋放指針指向的內存時,另一個對象的指針也就變成了野指針,這很容易導致內存管理的問題。
而深拷貝則是將指針指向的內存也進行複製,這樣新對象和原對象互不影響,互相獨立,即便其中一個對象釋放了指針指向的內存,也不會影響另一個對象。
三、實現賦值構造函數
在實現賦值構造函數前,我們需要重載賦值運算符。下面是一個示例代碼:
Test& operator=(const Test& t){
if(this == &t) return *this;
if(this->data != nullptr) delete[] data;
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
return *this;
}
需要注意的是,在重載賦值運算符中,需要進行自我賦值的判斷。如果不進行判斷的話,當對象自己賦值給自己時,就會導致指針指向的內存多次刪除,這會導致程序崩潰。因此,我們需要在賦值前判斷是否是自我賦值,如果是,則直接返回對象自身。
然後便可以進行賦值操作了。首先,需要刪除原先數據指針指向的內存。然後,需要重新分配內存,並將原始數據拷貝到新分配的內存區域中。最後,返回當前對象的引用。
if(this->data != nullptr) delete[] data;
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
return *this;
四、測試賦值構造函數的實現原理
下面是一個用於測試的代碼,首先我們定義了一個類Test, 其中包含有一個指針類型成員變量data,用於存儲int類型的數組,另一個成員變量len表示數組的長度。然後分別使用構造函數和賦值構造函數進行初始化,並可以通過輸出打印數組的值,來驗證賦值構造函數的實現原理。
#include <iostream>
using namespace std;
class Test{
public:
Test():data(nullptr), len(0) {}
~Test(){
if(data != nullptr)
delete[] data;
}
Test(const Test& t){
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
}
Test& operator=(const Test& t){
if(this == &t) return *this;
if(this->data != nullptr) delete[] data;
if(t.data != nullptr){
this->data = new int[t.len];
memcpy(this->data, t.data, sizeof(int)*t.len);
this->len = t.len;
}
return *this;
}
void printData(){
cout << "==========" << endl;
for(int i = 0; i < len; ++i){
cout << data[i] << " ";
}
cout << endl << "==========" << endl;
}
private:
int* data;
int len;
};
int main(){
Test t1;
t1.len = 3;
t1.data = new int[t1.len];
t1.data[0] = 1;
t1.data[1] = 2;
t1.data[2] = 3;
t1.printData();
Test t2 = t1;
t2.printData();
Test t3;
t3 = t1;
t3.printData();
return 0;
}
運行結果如下:
==========
1 2 3
==========
==========
1 2 3
==========
==========
1 2 3
==========
我們可以看到,三個Test對象的值均相等,通過輸出來證明賦值構造函數的實現原理是正確的。
五、總結
賦值構造函數是用於處理類中存在指針成員變量時進行賦值的構造函數,保證對象間的獨立性,以及在釋放指針指向的內存時的正確性。需要注意的是,在實現賦值構造函數時,需要判斷是否自我賦值。並且,為了保證賦值操作的有效性,需要將原先的指針指向的內存進行刪除,並重新分配內存,並將原先的數據拷貝到新分配的內存區域中。
原創文章,作者:JATV,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/138263.html