程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 條款14:在資源管理類中小心copying行為

條款14:在資源管理類中小心copying行為

編輯:C++入門知識

 

auto_ptr和tr1::shared_ptr的觀念表現在heap_based資源上。然而並非所有資源都是heap_based,對於非heap_based資源而言,需要建立自己的資源管理類。

假設我們使用C API函數出來類型為Mutex的互斥器對象(mutex objects),共有lock和unlock兩個函數。

void lock(Mutex* pm);		//鎖定pm所指的互斥器
void unlock(Mutex* pm);		//將互斥器解除鎖定

為確保絕不會忘記將一個被鎖住的Mutex解鎖,創建一個Lock class 來管理機鎖。這樣的class的基本結構由RAII守則支配,也就是“資源在構造期間獲得,在析構期間釋放”:

class Lock
{
public:
	explicit Lock(Mutex* pm)
		: mutexPtr(pm)
	{
		Lock(mutexPtr);		//獲得資源
	}
	~Lock()
	{
		unlock(mutexPtr);	//釋放資源
	}
private:
	Mutex *mutexPtr;
};

客戶對Lock的用法符合RAII方式:

Mutex m;
...
{
Lock ml(&m);    //鎖定互斥器
...
}   //在區塊末尾,自動解除互斥器鎖定

如果此時Lock對象被復制:

Lock ml1(&m);    //鎖定m
Lock ml2(ml1);   //將ml1復制到ml2上,會發生什麼?

可能有以下兩種選擇:

禁止復制:許多時候允許RAII對象復制並不合理:

 

如果沒有按需要定義復制構造函數和賦值操作符,那麼得到的結果通常是:非內存資源被創建一次,釋放多次。
禁止方式:將copying操作聲明為private。

class Lock : private Uncopyable  //禁止復制。見條款6
{ public: ...            //如前 };

如果需要復制,重新定義復制構造函數和賦值操作符是必須的。
怎麼寫它們是一個問題,具體的方案依賴於實際的需要,可以使用深拷貝,也可以使用類似於 shared_ptr 的引用計數機制,或者傳遞所有權。

對底層資源采用引用計數法

復制RAII對象時,將該資源的“被引用數”遞增。例:shared_ptr。

shared_ptr的缺省行為是“當引用次數為0時刪除所指物”,但是上面的例子我們想要的動作是解除lock而非刪除。
好在shared_ptr允許指定“刪除器”:

class Lock
{
public:
    explicit Lock(Mutex* pm):mutexPtr(pm,unlock)  //以某個mutex初始化shared_ptr,並以unlock函數為刪除器
    {lock(mutexPtr.get());}               //條款15

    ~Lock(){unlock(mutexPtr);}           //釋放資源
private:
    std::tr1::shared_ptr<Mutex> mutexPtr;
};

深度拷貝:
某些標准字符串類型是“指向heap內存”之指針構成。這樣的字符串對象被復制,不論指針或其所指內存都會被制作出一個復件。這樣的字符串展現深度復制行為。

轉移底部資源的擁有權:

auto_ptr奉行的復制意義:RAII對象被復制,資源的擁有權從被復制物轉移到目標物。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved