C++深拷貝和淺拷貝(C++深複製和淺複製)

2020-07-16 10:04:22
同類物件之間可以通過賦值運算子=互相賦值。如果沒有經過過載,=的作用就是把左邊的物件的每個成員變數都變得和右邊的物件相等,即執行逐個位元組拷貝的工作,這種拷貝叫作“淺拷貝”。

有的時候,兩個物件相等,從實際應用的含義上來講,指的並不應該是兩個物件的每個位元組都相同,而是有其他解釋,這時就需要對=進行過載。

上節我們定義了 String 類,並過載了=運算子,使得 char * 型別的字串可以賦值給 String 類的物件。完整程式碼如下:
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
    char * str;
public:
    String() :str(NULL) { }
    const char * c_str() const { return str; };
    String & operator = (const char * s);
    ~String();
};
String & String::operator = (const char * s)
//過載"="以使得 obj = "hello"能夠成立
{
    if (str)
        delete[] str;
    if (s) {  //s不為NULL才會執行拷貝
        str = new char[strlen(s) + 1];
        strcpy(str, s);
    }
    else
        str = NULL;
    return *this;
}
String::~String()
{
    if (str)
        delete[] str;
};
int main()
{
    String s;
    s = "Good Luck,"; //等價於 s.operator=("Good Luck,");
    cout << s.c_str() << endl;
    // String s2 = "hello!";   //這條語句要是不注釋掉就會出錯
    s = "Shenzhou 8!"; //等價於 s.operator=("Shenzhou 8!");
    cout << s.c_str() << endl;
    return 0;
}
對於上面的程式碼,如果讓兩個 String 物件相等(把一個物件賦值給另一個物件),其意義到底應該是什麼呢?是兩個物件的 str 成員變數都指向同一個地方,還是兩個物件的 str 成員變數指向的記憶體空間中存放的內容相同?如果把 String 物件理解為存放字串的物件,那應該是後者比較合理和符合習慣,而前者不但不符合習慣,還會導致程式漏洞。

按照上面程式碼中 String 類的寫法,下面的程式片段會引發問題:
String s1, s2;
s1 = "this";
s2 = "that";
s2 = s1;
執行完上面的第 3 行後,s1 和 s2 的狀態如圖 1 (a) 所示,它們的 str 成員變數指向不同的儲存空間。


圖1:淺拷貝導致的錯誤