深拷貝與淺拷貝的理解

2021-09-30 19:24:22 字數 2517 閱讀 4422

我們直接通過現象看問題!(下面的拷貝建構函式和賦值運算子過載是有問題的!!!)

#include

class

string

string

(const string& s)

:_str

(s._str)

//問題:1.記憶體洩漏 2.與拷貝建構函式類似

我們可以從監視視窗清楚的看到,s1和s2共用一塊記憶體空間。s3和s4共用一塊記憶體空間。

上面的**是淺拷貝的寫法

怎麼樣來理解這個問題(我們只看拷貝建構函式的例子,賦值運算子過載的原理基本一樣):首先給s1分配記憶體空間,位址為0x008f5308,然後放入該位址管理的資源"hello",當用s1拷貝構造s2時,呼叫拷貝建構函式,*str是乙個指標,直接用其進行賦值,所以等於物件s1、s2共用同一塊空間,那麼當物件生命週期結束時,需要呼叫析構函式對其資源進行釋放,相對於s1,優先釋放s2,那麼0x008f5308這段空間已被釋放,當再釋放s1時,那麼系統就會崩潰。

正確的寫法是下面的這種深拷貝

template

<

class

t>

void

swap

(t& a, t& b)

class

string

//傳統寫法

//string(const string& s)

// :_str(new char[strlen(s._str) + 1])

////現**法

string

(const string& s)

//傳統寫法

string&

operator=(

const string& s)

return

*this;}

//現**法1

/*string& operator=(const string& s)

return *this

}*///現**法2

我們可以清楚的看到深拷貝的物件的記憶體空間各不相同,當物件生命週期結束時,先呼叫析構函式對s4的資源進行清理,再呼叫析構函式清理s3,因為它們的記憶體空間各不相同,所以就不會發生衝突。

淺拷貝+引用計數來看看下面的**。

下面的**僅僅在單執行緒下時安全的

class

string

string

(string& s)

:_str

(s._str)

,_pcount

(s._pcount)

string&

operator=(

const string& s)

//共享資源

_str = s._str;

_pcount = s._pcount;

//計數+1++(

從上面我們可以看出,這樣也可以解決問題,就是加乙個pcount計數器,當有物件使用這塊空間時,計數+1,當該物件生命週期結束時,計數-1,當該計數為0時,就釋放這塊空間,這裡這個計數不能通過靜態成員變數來實現,因為靜態成員變數時全域性作用域的,當不發生拷貝構造時,指向不同空間的不同物件也使用同乙個計數count,就會出現問題

陣列深拷貝 淺拷貝與深拷貝(個人理解)

深拷貝和淺拷貝的區別1 淺拷貝只複製一層物件的屬性 值引用 場景 對於只有一層結構的array和object想要拷貝乙個副本時使用 淺拷貝的實現方式1 es6 的 object.assign 當object只有一層時是深拷貝 var obj var initobj object.assign obj...

淺拷貝,深拷貝的理解

淺拷貝 淺拷貝是將物件的每個屬性進行依次複製,當物件的屬性值是引用型別,實質複製的是其引用,指向的值改也會跟著變化,淺拷貝只拷貝一層 深拷貝 深拷貝複製變數值,對於非基本型別的變數,則遞迴至基本型別變數後,在複製,深拷貝後的物件與原來的物件是完全隔離的,互不影響,深拷貝是層層拷貝 淺拷貝 操作 簡單...

「淺拷貝」與「深拷貝」

c 中物件的複製就如同 轉殖 用乙個已有的物件快速地複製出多個完全相同的物件。一般而言,以下三種情況都會使用到物件的複製 1 建立乙個新物件,並用另乙個同類的已有物件對新物件進行初始化,例如 cpp view plain copy class rect rect rect1 rect rect2 r...