C++String類寫時(shí)拷貝

   維基百科:

在溫泉等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作專業(yè)公司,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站建設(shè),網(wǎng)絡(luò)營(yíng)銷推廣,成都外貿(mào)網(wǎng)站建設(shè)公司,溫泉網(wǎng)站建設(shè)費(fèi)用合理。

   寫入時(shí)復(fù)制(英語(yǔ):Copy-on-write,簡(jiǎn)稱COW)是一種計(jì)算機(jī)程序設(shè)計(jì)領(lǐng)域的優(yōu)化策略。其核心思想是,如果有多個(gè)調(diào)用者(callers)同時(shí)要求相同資源(如內(nèi)存或磁盤上的數(shù)據(jù)存儲(chǔ)),他們會(huì)共同獲取相同的指針指向相同的資源,直到某個(gè)調(diào)用者試圖修改資源的內(nèi)容時(shí),系統(tǒng)才會(huì)真正復(fù)制一份專用副本(private copy)給該調(diào)用者,而其他調(diào)用者所見到的最初的資源仍然保持不變。這過程對(duì)其他的調(diào)用者都是透明的(transparently)。此作法主要的優(yōu)點(diǎn)是如果調(diào)用者沒有修改該資源,就不會(huì)有副本(private copy)被創(chuàng)建,因此多個(gè)調(diào)用者只是讀取操作時(shí)可以共享同一份資源。


    String類中的寫時(shí)拷貝技術(shù)是指用淺拷貝的方法拷貝其他對(duì)象,多個(gè)指針指向同一塊空間,只有當(dāng)對(duì)其中一個(gè)對(duì)象修改時(shí),才會(huì)開辟一個(gè)新的空間給這個(gè)對(duì)象,和它原來(lái)指向同一空間的對(duì)象不會(huì)受到影響。寫時(shí)拷貝的效率遠(yuǎn)高于深拷貝。

    可以通過增加一個(gè)成員變量count來(lái)實(shí)現(xiàn)寫時(shí)拷貝,這個(gè)變量叫做引用計(jì)數(shù),統(tǒng)計(jì)這塊空間被多少個(gè)對(duì)象的_str同時(shí)指向。當(dāng)用指向這塊空間的對(duì)象拷貝一個(gè)新的對(duì)象出來(lái)時(shí)count+1,當(dāng)指向這塊空間的一個(gè)對(duì)象指向別的空間或析構(gòu)時(shí)count-1。只有當(dāng)count等于0時(shí)才可以釋放這塊空間,否則說(shuō)明還有其他對(duì)象指向這塊空間,不能釋放。

    count應(yīng)該是什么類型呢?如果是int類型。

class String
{
	public:
	String(const char* str)
		:_str(new char[strlen(str)+1])
		,_count(1)
	{
		strcpy(_str, str);
	}

	String(String& s)
		:_str(s._str)
	{
		++s._count;
		_count = s._count;
	}

	~String()
	{
		if (--_count == 0)
		{
			delete[] _str;
		}
	}

private:
	char* _str;
	int _count;
};



void Test()
{
	String s1("aaaaaaaaa");
	String s2(s1);
}

雖然s1._count和s2._count都等于2,但是當(dāng)s2執(zhí)行析構(gòu)函數(shù)后

C++ String類寫時(shí)拷貝

    現(xiàn)在只剩下s1一個(gè)對(duì)象指向這塊空間,s1._count和s2._count應(yīng)該都變?yōu)?,但是s1._count沒有改變,查看s1._count和s2._count的地址發(fā)現(xiàn)它們并不是同一個(gè)地址,改變count只對(duì)當(dāng)前對(duì)象有效,其他對(duì)象不會(huì)受到影響,無(wú)法實(shí)現(xiàn)引用計(jì)數(shù)。

這說(shuō)明count是公共的,可以被多個(gè)對(duì)象同時(shí)訪問的。如果是static int類型

class String
{
	public:
	String(const char* str)
		:_str(new char[strlen(str)+1])
	{
		_count = 1;
		strcpy(_str, str);
	}

	String(String& s)
		:_str(s._str)
	{
		++_count;
	}

	~String()
	{
		if (--_count == 0)
		{
			delete[] _str;
		}
	}

private:
	char* _str;
	static int _count;
};

int String::_count = 0;

void Test()
{
	String s1("aaaaaaaaa");
	String s2(s1);
	String s3(s2);

	String s4("bbbbbbbbb");
	String s5(s4);
}

    現(xiàn)在s1、s2、s3的引用計(jì)數(shù)應(yīng)該是3,s4、s5的引用計(jì)數(shù)應(yīng)該是2。

C++ String類寫時(shí)拷貝

    但是結(jié)果不正確。原因是s1、s2、s3指向同一塊空間后count增加到3,構(gòu)造s4時(shí)又把count設(shè)置為1,s4拷貝構(gòu)造s5后count增加到2。說(shuō)明這5個(gè)對(duì)象共用一個(gè)count,不能實(shí)現(xiàn)引用計(jì)數(shù)。

    如果一個(gè)對(duì)象第一次開辟空間存放字符串時(shí)再開辟一塊新的空間存放引用計(jì)數(shù),當(dāng)它拷貝構(gòu)造其他對(duì)象時(shí)讓其他對(duì)象的引用計(jì)數(shù)都指向存放引用計(jì)數(shù)的同一塊空間,count設(shè)置為int*類型,就可以實(shí)現(xiàn)引用計(jì)數(shù)了。

C++ String類寫時(shí)拷貝

class String
	{
	public:
		String(const char* str)
			:_str(new char[strlen(str)+1])
			,_pCount(new int(1))
		{
			strcpy(_str, str);
		}

		String(String& s)
			:_str(s._str)
			,_pCount(s._pCount)
		{
			++(*_pCount);
		}

		String& operator=(const String& s)
		{
			if (/*this != &s ||*/ _str != s._str) //防止自己給自己賦值,或自己拷貝的對(duì)象給自己賦值
			{
				//釋放原對(duì)象
				if (--(*_pCount) == 1)
				{
					delete _pCount;
					delete[] _str;
				}

				//淺拷貝增加引用計(jì)數(shù)
				_str = s._str;
				_pCount = s._pCount;
				++(*_pCount);
			}

			return *this;
		}

		~String()
		{
			if (--*_pCount == 0)
			{
				delete _pCount;
				delete[] _str;
			}
		}

	protected:
		char* _str;
		int* _pCount;
	};

   但是這種方法也存在不足:

    1、它每次new兩塊空間,創(chuàng)建多個(gè)對(duì)象時(shí)效率較低于下面這種方法;

    2、它多次分配小塊空間,容易造成內(nèi)存碎片化,導(dǎo)致分配不出來(lái)大塊內(nèi)存。

    還有一種方法是在開辟_str時(shí)多開辟4個(gè)字節(jié),在這塊空間的頭部保存引用計(jì)數(shù)。

    C++ String類寫時(shí)拷貝

    

	class String
	{
	public:
		String(const char* str)
			:_str(new char[strlen(str)+5])
		{
			_str += 4;
			strcpy(_str, str);

			//(*(int*)(_str-4)) = 1;
			_GetRefCount(_str) = 1;
		}

		String(const String& s)
			:_str(s._str)
		{
			//*((int*)(_str-4)) += 1;
			_GetRefCount(_str)++;
		}

		String& operator=(const String& s)
		{
			if (/*this != &s ||*/ _str != s._str) //防止自己給自己賦值,或自己拷貝的對(duì)象給自己賦值
			{
				/*if (--(*(int*)(_str-4)) == 0)
				{
					delete[] (_str-4);
				}*/
				_Release();

				_str = s._str;
				++(*(int*)(s._str-4));
			}

			return *this;
		}

		~String()
		{
			/*if (--(*(int*)(_str-4)) == 0)
			{
				delete[] (_str-4);
			}*/
			_Release();
		}

		//operator[]的特殊性,讀時(shí)也拷貝
		char& operator[](size_t index)
		{
			//當(dāng)引用計(jì)數(shù)大于1,需要寫時(shí)拷貝
			if (_GetRefCount(_str) > 1)
			{
				char* tmp = new char[strlen(_str) + 5];
				--_GetRefCount(_str); //new空間后再減引用計(jì)數(shù),防止new空間失敗
				tmp += 4;
				_GetRefCount(tmp) = 1;

				_str = tmp;
			}
			return _str[index];
		}

	protected:
		int& _GetRefCount(char* _ptr)
		{
			return *((int*)(_ptr-4));
		}

		//--引用計(jì)數(shù),如果引用計(jì)數(shù)等于0,釋放
		void _Release()
		{
			if (/*--(*(int*)(_str-4))*/--_GetRefCount(_str) == 0)
			{
				delete[] (_str-4);
			}
		}

	protected:
		char* _str;
	};

    

void COWTest()
	{
		String s1("aaaaaaaaaaa");
		String s2(s1);
		String s3(s1);

		//operator[]的特殊性,讀時(shí)也拷貝
		cout<<s1[0]<<endl;
		
		//寫時(shí)拷貝
		s1[0] = '1';
	}

    當(dāng)對(duì)s1修改后,s1指向新拷貝出來(lái)的空間。

C++ String類寫時(shí)拷貝

C++ String類寫時(shí)拷貝

C++ String類寫時(shí)拷貝

C++ String類寫時(shí)拷貝

    

    推薦文章:  《C++ STL string的Copy-On-Write技術(shù)》

當(dāng)前標(biāo)題:C++String類寫時(shí)拷貝
地址分享:http://www.muchs.cn/article14/ghgsge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、虛擬主機(jī)、定制開發(fā)、小程序開發(fā)、企業(yè)網(wǎng)站制作、搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)