在深入這前,通過上述的示範,我們應該知道在string類中,要實作寫時才拷貝,需要解決兩個問題,一個是記憶體共享,一個是Copy-On-Wirte,這兩個主題會讓我們産生許多疑問,還是讓我們帶着這樣幾個問題來學習吧:
1、 Copy-On-Write的原理是什麼?
2、 string類在什麼情況下才共享記憶體的?
3、 string類在什麼情況下觸發寫時才拷貝(Copy-On-Write)?
4、 Copy-On-Write時,發生了什麼?
5、 Copy-On-Write的具體實作是怎麼樣的?
喔,你說隻要看一看STL中stirng的源碼你就可以找到答案了。當然,當然,我也是參考了string的父模闆類basic_string的源碼。但是,如果你感到看STL的源碼就好像看機器碼,并嚴重打擊你對C++自信心,乃至産生了自己是否懂C++的疑問,如果你有這樣的感覺,那麼還是繼續往下看我的這篇文章吧。
OK,讓我們一個問題一個問題地探讨吧,慢慢地所有的技術細節都會浮出水面的。
有一定經驗的程式員一定知道,Copy-On-Write一定使用了“引用計數”,是的,必然有一個變量類似于RefCnt。當第一個類構造時,string的構造函數會根據傳入的參數從堆上配置設定記憶體,當有其它類需要這塊記憶體時,這個計數為自動累加,當有類析構時,這個計數會減一,直到最後一個類析構時,此時的RefCnt為1或是0,此時,程式才會真正的Free這塊從堆上配置設定的記憶體。
是的,引用計數就是string類中寫時才拷貝的原理!
不過,問題又來了,這個RefCnt該存在在哪裡呢?如果存放在string類中,那麼每個string的執行個體都有各自的一套,根本不能共有一個RefCnt,如果是聲明成全局變量,或是靜态成員,那就是所有的string類共享一個了,這也不行,我們需要的是一個“民主和集中”的一個解決方法。這是如何做到的呢?呵呵,人生就是一個糊塗後去探知,知道後和又糊塗的循環過程。别急别急,在後面我會給你一一道來的。
這個問題的答案應該是明顯的,根據常理和邏輯,如果一個類要用另一個類的資料,那就可以共享被使用類的記憶體了。這是很合理的,如果你不用我的,那就不用共享,隻有你使用我的,才發生共享。
使用别的類的資料時,無非有兩種情況,1)以别的類構造自己,2)以别的類指派。第一種情況時會觸發拷貝構造函數,第二種情況會觸發指派操作符。這兩種情況我們都可以在類中實作其對應的方法。對于第一種情況,隻需要在string類的拷貝構造函數中做點處理,讓其引用計數累加;同樣,對于第二種情況,隻需要重載string類的指派操作符,同樣在其中加上一點處理。
唠叨幾句:
1)構造和指派的差别
對于前面那個例程中的這兩句:
string str1 = "hello world";
string str2 = str1;
不要以為有“=”就是指派操作,其實,這兩條語句等價于:
string str1 ("hello world"); //調用的是構造函數
string str2 (str1); //調用的是拷貝構造函數
如果str2是下面的這樣情況:
string str2; //調用參數預設為空串的構造函數:string str2(“”);
str2 = str1; //調用str2的指派操作:str2.operator=(str1);
2) 另一種情況
char tmp[]=”hello world”;
string str1 = tmp;
string str2 = tmp;
這種情況下會觸發記憶體的共享嗎?想當然的,應該要共享。可是根據我們前面所說的共享記憶體的情況,兩個string類的聲明和初始語句并不符合我前述的兩種情況,是以其并不發生記憶體共享。而且,C++現有特性也無法讓我們做到對這種情況進行類的記憶體共享。
哦,什麼時候會發現寫時才拷貝?很顯然,當然是在共享同一塊記憶體的類發生内容改變時,才會發生Copy-On-Write。比如string類的[]、=、+=、+、操作符指派,還有一些string類中諸如insert、replace、append等成員函數,包括類的析構時。
修改資料才會觸發Copy-On-Write,不修改當然就不會改啦。這就是托延戰術的真谛,非到要做的時候才去做。
我們可能根據那個通路計數來決定是否需要拷貝,參看下面的代碼:
If ( RefCnt>0 ) {
char* tmp = (char*) malloc(strlen(_Ptr)+1);
strcpy(tmp, _Ptr);
_Ptr = tmp;
}
上面的代碼是一個假想的拷貝方法,如果有别的類在引用(檢查引用計數來獲知)這塊記憶體,那麼就需要把更改類進行“拷貝”這個動作。
我們可以把這個拷的運作封裝成一個函數,供那些改變内容的成員函數使用。
本文轉自 haoel 51CTO部落格,原文連結:http://blog.51cto.com/haoel/124637,如需轉載請自行聯系原作者