1、深淺拷貝的使用時機:
創新互聯于2013年成立,是專業互聯網技術服務公司,擁有項目做網站、成都網站建設網站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元金湖做網站,已為上家服務,為金湖各地企業和個人服務,聯系電話:028-86922220淺拷貝:對只讀數據共用一份空間,且只釋放一次空間;
深拷貝:數據的修改,的不同空間;
2、引用計數器模型
使用變量use_count,來記載初始化對象個數;
static模型(此處只用淺拷貝與淺賦值)
#include<iostream> #include<string.h> #include<malloc.h> using namespace std; class String{ public: String(const char *str = ""){ if(str == NULL){ data = new char; data[0] = 0; }else{ data = new char[strlen(str) + 1]; strcpy(data,str); } use_count++; //每新創建一個對象,對引用計數器++; } String(const String &s){ data = s.data; use_count++; //創建出新的對象,use_count++; } //此處先不寫賦值語句 ~String(){ if(--use_count == 0){ //當引用計數器減為0時,就是每次行析構對象時,都對它減一次,直到為0才釋放空間, delete []data; data = NULL; } } public: char* GetString()const{ return data; } private: char *data; static int use_count; //此處use_count只有一份,負責記載創建了多少個對象; }; int String::use_count = 0; //C++中的靜態變量全局只有一份,可以再類外進行初始化; int main(void) { String s1("hello"); cout<<s1.GetString()<<endl; String s2; s2 = s1; //淺賦值,調用默認的; cout<<s2.GetString()<<endl; String s3("xyz"); //創建t3對象,要出問題了;(對其就只創建出來,不在進行賦值語句等操作);此時的情況是:已經有兩個對象,其成員data指向同一空間,此時又有一個data指向另一個空 //間,但是use_count為0才釋放空間,只釋放一份,所以肯定有內存泄漏!!! return 0; }
上面的static淺拷貝其實存在很大的問題,當t3對象創建時,use_count會加1;
當調用析構函數時,每次減1,為0時,釋放空間,
3、寫時拷貝
淺拷貝與深拷貝聯合使用,看實際需求對其編寫,此時我希望,對數據讀時共用一份數據,需要修改時,在單獨開辟空間進行修改,在進行改寫,并且對象(初始化)應該有自己的data和use_count,賦值語句時共用一份就行,此時就需要句柄了,這就是寫時拷貝;
具體完整代碼如下:
#include<iostream> #include<malloc.h> #include<string.h> using namespace std; class String; class String_rep{ // 這個類是封裝在內部供我們程序員自己使用的。 friend class String; //友元類,可以訪問私有數據。 public: String_rep(const char *str = ""):use_count(0){ //構造函數的初始化 if(str == NULL){ data = new char[1]; data[0] = 0; }else{ data = new char[strlen(str)+1]; strcpy(data,str); } } String_rep(const String_rep &rep); String_rep& operator=(const String_rep &rep); ~String_rep(){ delete []data; data = NULL; } public: void increment(){ use_count++; } void decrement(){ //這個函數至關重要,寫了一個釋放空間的函數,要在其后賦值語句中使用; if(--use_count == 0) delete this; } int use_count_()const{ return use_count; } public: char *getdata()const{ return data; } private: char *data; int use_count; }; class String{ public: String(const char *str = ""):rep(new String_rep(str)){ rep->increment(); } String(const String &s){ rep = s.rep; rep->increment(); } String& operator=(const String &s){ if(this != &s){ rep->decrement(); rep = s.rep; rep->increment(); } return *this; } ~String(){ rep->decrement(); } public: int use_count()const{ return rep->use_count_(); } void print()const{ cout<<rep->data<<endl; } void toupper(){ //這個函數提供的意義:對其要改的對象重新申請空間,進行改寫,使相互之間不影響。 if(rep->use_count_() > 1){ //對象個數大于1才進行拷貝出來重新寫,只有一個就直接在其上進行修改。 String_rep *new_rep = new String_rep(rep->data); this->rep->decrement(); rep = new_rep; rep->increment(); } char *pch = rep->data; while(*pch){ *pch -= 32; pch++; } } private: String_rep *rep; // 句柄 }; int main(){ String s1("hello"); String s2 = s1; String s3("xyz"); s3 = s2; s1.toupper(); s1.print(); cout<<"s1 count = "<<s1.use_count()<<endl; s2.print(); cout<<"s2 count = "<<s2.use_count()<<endl; s3.print(); cout<<"s3 count = "<<s3.use_count()<<endl; return 0; }
以上的代碼就可以達到目的,每次創建對象都有自己的data和use_count(調用構造函數),在賦值語句時先釋放原有空間,在進行淺拷貝,構造函數時也是淺拷貝,對其進行了各自空間的管理與釋放,并且在修改數據時拷貝出來一份即可。
分析如下:
關于以上還有個問題:就是:
void decrement(){ if(--use_count == 0) delete this; }
為什么不在String類的析構函數中寫delete呢?
原因:析構函數只有在對象釋放是才調用,而在此時,通過賦值語句要釋放空間,析構函數此時就不能及時釋放原有空間,會造成內存泄漏,所以寫一個釋放空間的函數,內部有delete,會先調用析構函數,達到了及時釋放空間的目的!
以上只是對寫時拷貝的粗淺理解。
另外有需要云服務器可以了解下創新互聯scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業上云的綜合解決方案,具有“安全穩定、簡單易用、服務可用性高、性價比高”等特點與優勢,專為企業上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。
標題名稱:寫時拷貝引用計數器模型-創新互聯
地址分享:http://vcdvsql.cn/article46/hsehg.html
成都網站建設公司_創新互聯,為您提供服務器托管、品牌網站設計、商城網站、用戶體驗、網站策劃、微信小程序
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯