1. 程式人生 > >std::shared_ptr 和 std::weak_ptr的用法以及引用計數的迴圈引用問題

std::shared_ptr 和 std::weak_ptr的用法以及引用計數的迴圈引用問題

    在std::shared_ptr被引入之前,C++標準庫中實現的用於管理資源的智慧指標只有std::auto_ptr一個而已。std::auto_ptr的作用非常有限,因為它存在被管理資源的所有權轉移問題。這導致多個std::auto_ptr型別的區域性變數不能共享同一個資源,這個問題是非常嚴重的哦。因為,我個人覺得,智慧指標記憶體管理要解決的根本問題是:一個堆物件(或則資源,比如檔案控制代碼)在被多個物件引用的情況下,何時釋放資源的問題。何時釋放很簡單,就是在最後一個引用它的物件被釋放的時候釋放它。關鍵的問題在於無法確定哪個引用它的物件是被最後釋放的。std::shared_ptr確定最後一個引用它的物件何時被釋放的基本想法是:對被管理的資源進行引用計數,當一個shared_ptr物件要共享這個資源的時候,該資源的引用計數加1,當這個物件生命期結束的時候,再把該引用技術減少1。這樣當最後一個引用它的物件被釋放的時候,資源的引用計數減少到0,此時釋放該資源。下邊是一個shared_ptr的用法例子:

#include <iostream>
#include <memory>

class Woman;
class Man{
private:
	std::weak_ptr<Woman> _wife;
	//std::shared_ptr<Woman> _wife;
public:
	void setWife(std::shared_ptr<Woman> woman){
		_wife = woman;
	}

	void doSomthing(){
		if(_wife.lock()){
		}
	}

	~Man(){
		std::cout << "kill man\n";
	}
};

class Woman{
private:
	//std::weak_ptr<Man> _husband;
	std::shared_ptr<Man> _husband;
public:
	void setHusband(std::shared_ptr<Man> man){
		_husband = man;
	}
	~Woman(){
		std::cout <<"kill woman\n";
	}
};


int main(int argc, char** argv){
	std::shared_ptr<Man> m(new Man());
	std::shared_ptr<Woman> w(new Woman());
	if(m && w) {
		m->setWife(w);
		w->setHusband(m);
	}
	return 0;
}
    在Man類內部會引用一個Woman,Woman類內部也引用一個Man。當一個man和一個woman是夫妻的時候,他們直接就存在了相互引用問題。man內部有個用於管理wife生命期的shared_ptr變數,也就是說wife必定是在husband去世之後才能去世。同樣的,woman內部也有一個管理husband生命期的shared_ptr變數,也就是說husband必須在wife去世之後才能去世。這就是迴圈引用存在的問題:husband的生命期由wife的生命期決定,wife的生命期由husband的生命期決定,最後兩人都死不掉,違反了自然規律,導致了記憶體洩漏。

     解決std::shared_ptr迴圈引用問題的鑰匙在weak_ptr手上。weak_ptr物件引用資源時不會增加引用計數,但是它能夠通過lock()方法來判斷它所管理的資源是否被釋放。另外很自然地一個問題是:既然weak_ptr不增加資源的引用計數,那麼在使用weak_ptr物件的時候,資源被突然釋放了怎麼辦呢?呵呵,答案是你根本不能直接通過weak_ptr來訪問資源。那麼如何通過weak_ptr來間接訪問資源呢?答案是:在需要訪問資源的時候weak_ptr為你生成一個shared_ptr,shared_ptr能夠保證在shared_ptr沒有被釋放之前,其所管理的資源是不會被釋放的。建立shared_ptr的方法就是lock()方法。

    細節:shared_ptr實現了operator bool() const方法來判斷一個管理的資源是否被釋放。


相關推薦

std::shared_ptr std::weak_ptr用法以及引用計數迴圈引用問題

    在std::shared_ptr被引入之前,C++標準庫中實現的用於管理資源的智慧指標只有std::auto_ptr一個而已。std::auto_ptr的作用非常有限,因為它存在被管理資源的所有權轉移問題。這導致多個std::auto_ptr型別的區域性變數不能共享

std::shared_ptr std::weak_ptr引用計數迴圈引用問題

shared維護了一個指向control block的指標,control block內部包含了智慧指標物件的引用個數。weak_ptr 是一種不控制物件生命週期的智慧指標, 它指向一個 shared_ptr 管理的物件. 進行該物件的記憶體管理的是那個強引用的 shared

C++中的仿函式,std::functionbind()的用法

1.仿函式:又叫std::function,是C++中的一個模板類 2.C語言中的函式指標: int  add(int a,int b) {   return a+b; } typedef int (*func)(int,int);//給函式型別定義別名

(轉)用C++11的std::async代替執行緒的建立, 以及std::future,std::promisestd::packaged_task的使用

c++11中增加了執行緒,使得我們可以非常方便的建立執行緒,它的基本用法是這樣的: void f(int n); std::thread t(f, n + 1); t.join(); 但是執行緒畢竟是屬於比較低層次的東西,有時候使用有些不便,比如我希望獲取執

C++11 中std::functionstd::bind的用法

關於std::function 的用法: 其實就可以理解成函式指標 1. 儲存自由函式 void printA(int a) { cout<<a<<endl; } std::function<void(int a)

執行緒與互斥鎖(C++11中std::threadstd::mutex的用法

執行緒 0 首先是曾經在MultiCMOS專案中用到的: #include <thread> //包含標頭檔案 class IDataProcessUnit { protected:

實戰c++中的vector系列--對vector&lt;自己定義類&gt;使用std::find std::find_if 算法

++ pac price key fadein 輸出 var getitem mod 之前博客講了一些關於std::find和std::find_ if的一些使用方法。可是沒有講述對於vector中存儲的是自己定義的類。那麽怎麽樣使用std::find和

sedawk的用法以及區別

sed和awk sed主要處理“行問題”。 awk主要處理“列問題”。 sed實例:sed -n "2p" /file 輸出file文件中的第二行 awk實例:awk -F= ‘BEGIN{print "hello"}{print

第11課 std::bindstd::function(2)_std::bind綁定器

pan std name iostream emf end cnblogs left eid 1. 溫故知新:std::bind1st和std::bind2nd (1)bind1st、bind2nd首先它們都是函數模板,用於將參數綁定到可調用對象(如函數、仿函數等)的第1個

Action Func 的用法以及區別

delegate class div clas 返回 span pre console 技術分享 Action 無返回值 Func 有返回值,且最後一個參數為返回值 Action用法 public static void test(string s)

基於std::mutex std::lock_guard std::condition_variable std::async實現的簡單同步隊列

有關 com urn list 占用空間 當前 條件變量 size 多線程 C++多線程編程中通常會對共享的數據進行寫保護,以防止多線程在對共享數據成員進行讀寫時造成資源爭搶導致程序出現未定義的行為。通常的做法是在修改共享數據成員的時候進行加鎖--mutex。在使用鎖的時

muduo庫中的核心:std::bindstd::function

muduo main ons 源碼 綁定 func 靜態成員 con 函數 最近在讀完陳碩大牛的《Linux多線程服務端編程》以及muduo源碼後,對其中的一些實現細節有著十分深刻的印象,尤其是使用std::bind和std::function的回調技術。可以說,這兩個大殺

Variableget_variable的用法以及區別

沒有 constant src 分開 true iba 順序 () lse 在tensorflow中,可以使用tf.Variable來創建一個變量,也可以使用tf.get_variable來創建一個變量,但是在一個模型需要使用其他模型的變量時,tf.get_variable

std::mapstd::multimap的使用總結

Map和Multimap   Map和Multimap(下文統稱Map)將key/value作為元素進行管理,邏輯上是一種鍵值對映關係,即資料結構中雜湊表。它們可以根據key的排序規則進行自動元素排序,Multimap允許元素重複,而Map不允許。   在使用Map和Multima

STL 1–迭代器std::begin()std::end()使用

迭代器是一個行為類似於指標的模板類物件。只需要迭代器iter指向一個有效物件,就可以通過使用*iter解引用的方式來獲取一個物件的引用。通常會使用一對迭代器來定義一段元素,可以是任意支援迭代器物件的元素,一段元素是一個通過起始迭代器指向第一個元素,通過結束迭代器指向最後一個元素的後一個位置的元素序列。一般使用

@RequestBody@ResponseBody的用法以及Stringify()的作用

首先,在專案的前後互動中json資料格式比較常用,普遍認為json格式比較簡單,易於解析 如果我們在前端傳送一個ajax請求的話 可以看到是用json格式向後臺傳請求引數,那麼後臺需要採用@RequestBody來處理請求的json格式資料,將json資料轉換為java物件,否則spr

C++:探索std::mapstd::unordered_map中的新增操作

std::map和std::unordered_map主要提供如下幾種新增操作: try_emplace ()   (C++17) emplace () insert() [] = 下面給出一段測試程式碼,觀察物件在新增到std::map中時,

C++中的std::lock_guardstd::unique_lock

std::lock_guard 這是最簡單的一個管理鎖的物件。只有構造和解構函式,在構造的時候加鎖,析構的時候解鎖,解鎖後就不能使用該物件再加鎖了。可以避免使用std::mutex時忘記解鎖的情況,同時可以方便處理異常。 簡單的例項: #include <iostrea

std::mutex std::lock_guard 小例子

https://blog.csdn.net/yasi_xi/article/details/19205461 參考:http://stackoverflow.com/questions/21771860/how-to-make-sure-locker-be-unlock-in-c-which-s

c++ 之智慧指標:儘量使用std::make_uniquestd::make_shared而不直接使用new

關於make_unique的構造及使用例程,MSDN的講解非常詳細 (https://msdn.microsoft.com/zh-cn/library/dn439780.aspx ) 使用過程中,主要有這麼幾個關鍵點: 1.  make_unique 同 uni