我們直接通過現象看問題!(下面的拷貝建構函式和賦值運算子過載是有問題的!!!)
#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...