深淺拷貝——string

對於一般的對象,如:

int a = b;

int c = 5;

它們之間的賦值,複製很簡單,到對於類對象來說,其內部存在各種成員變量,他的複製,賦值就不是如此的簡單,如果處理不當,就會出現各種問題。

我們首先來看一下下面的代碼:

#include<iostream>

using namespace std;

#include<string.h>

class String

{

public:

String(const char* ptr)

:_ptr(new char[strlen(ptr) + 1])

{

strcpy(_ptr, ptr);

cout << "String" << endl;

                cout << _ptr << endl;

}

String(const String& ptr)

:_ptr(ptr._ptr)

{}

String& operator=(const String& ptr)

{

if (this != &ptr)

{

_ptr = ptr._ptr;

}

return *this;

}

~String()

{

cout << "~String" << endl;

delete[] _ptr;

}

private:

char * _ptr;

};

void Test()

{

String s("hello");

String s2(s);

}

int main()

{

Test();

return 0;

}

wKioL1dFD1iTB1_nAAA0LAZCceY727.png

可以看到,這裏對同一對象析構了兩次,我們通過下面的圖來對這個現象進行解釋:

wKiom1dFEbPzOSdsAAAbXp5pzrM042.png

在進行對象複製後,事實上s、s2裏的成員指針_ptr都指向了一塊內存空間(即內存空間共享了),在s1析構時,delete了成員指針_ptr所指向的內存空間,而s2析構時同樣指向(此時已變成野指針)並且要釋放這片已經被s1析構函數釋放的內存空間,這就讓同樣一片內存空間釋放了兩次 ,從而出錯。而淺拷貝還存在着一個問題,因爲一片空間被兩個不同的子對象共享了,只要其中的一個子對象改變了其中的值,那另一個對象的值也跟着改變了。

在這裏呢我們找到了深拷貝來解決這個問題。

下面是深拷貝的拷貝構造函數代碼:

String(const String& ptr)

:_ptr(new char[strlen(ptr._ptr) + 1])

{

strcpy(_ptr, ptr._ptr);

}

這裏通過重新開闢一段空間來解決淺拷貝中析構兩次的情況。

在淺拷貝中還存在其他的一些問題,比如賦值運算符重載,他也是s,s1,兩個對象指向同一塊內存空間。在析構時同樣會出現問題。還有析構函數,如果這塊空間爲NULL,又怎麼能進行析構呢!

我們給出深拷貝的函數代碼:

class String

{

public:

String(const char* ptr)

:_ptr(new char[strlen(ptr) + 1])

{

strcpy(_ptr, ptr);

}

String(const String& ptr)

:_ptr(new char[strlen(ptr._ptr) + 1])

{

strcpy(_ptr, ptr._ptr);

}

String& operator=(const String& ptr)

{

if (this != &ptr)

{

                        delete[] _ptr;

char* tmp = new char[strlen(ptr._ptr) + 1];

strcpy(tmp, ptr._ptr);

_ptr = tmp;

}

return *this;

}

~String()

{

if (_ptr)

{

delete[] _ptr;

}

}

private:

char* _ptr;

};

void Test()

{

String s("hello");

String s2(s);

String s3("11111");

s3 = s;

}

int main()

{

Test();

return 0;

}

通過深拷貝我們就能解決淺拷貝的問題。

對深拷貝中的賦值運算符重載我們做以下說明:

1.進入賦值運算符重載,我們首先需要判斷該對象是不是自己給自己賦值,自己給自己賦值從賦值上來說也沒錯,但是在調用析構函數時又怎該去析構呢?不是又給同一對象析構兩次嗎?

2.賦值運算符重載的深層理解

String& operator=(const String& ptr)

s3 = s;

賦值運算符重載傳參是其實是這樣的:s3.operator=(&s3,s),&s3其實就是this指針,在實現賦值運算符重載的過程中,首先析構掉s3原本空間的內容,然後開闢一段新空間,把s的內容複製到新空間中,再把新空間的內容給給s3,完成賦值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章