【C++】智能指針簡述(五):解決循環引用的weak_ptr


  總結一下前文內容:

  1.智能指針通過RAII方法來管理指針:構造對象時,完成資源初始化;析構對象時,對資源進行清理及汕尾.

  2.auto_ptr,通過“轉移所有權”來防止析構一塊內存多次.(如何轉移?詳情看第二篇文章)

  3.scoped_ptr,不“轉移所有權”而是禁止拷貝/賦值對象.(C++如何禁止拷貝對象?詳情看第三篇文章)

  4.shared_ptr,通過"引用計數"的方法,來完成對象的拷貝/賦值.(引用計數怎么實現?詳情看上篇文章)

  大致總結了一下前文后,我們開始討論今天的內容:解決智能指針的循環引用問題!

  我們先來看一下這樣的場景:

template<typename T>
struct ListNode{
	T _value;
	std::shared_ptr<ListNode> _prev;
	std::shared_ptr<ListNode> _next;

	ListNode(const T & value)
		:_value(value)
		,_prev(NULL)
		,_next(NULL){}

	~ListNode(){
		std::cout<<"~ListNode()"<<std::endl;
	}
};

void TestWeekPtr(){
	std::shared_ptr<ListNode<int>> sp1(new ListNode<int>(10)); 
	std::shared_ptr<ListNode<int>> sp2(new ListNode<int>(20));
	sp1->_next = sp2;
	sp2->_prev = sp1;
	//構成死鎖,出了函數作用域,也沒有調用析構函數
	std::cout<<sp1.use_count()<<std::endl;	//sp1的引用計數
	std::cout<<sp2.use_count()<<std::endl;	//sp2的引用計數
}

  sp1指向sp2、sp2又指向sp1,這種情況,就好像兩個人打架:互相抓住對方耳朵,A說你先松手,你不松我就不松;B說你先松,你不松我也不松.就這樣一直僵持着.....

  那么,我們如何解決這樣的問題呢?

  用weak_ptr!!!

template<typename T>
struct ListNode{
	T _value;
	weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;
	
	ListNode(const T & value)
		:_value(value)
		,_prev(NULL)
		,_next(NULL){}

	~ListNode(){
		std::cout<<"~ListNode()"<<std::endl;
	}
};
void TestWeekPtr(){
	std::shared_ptr<ListNode<int>> sp1(new ListNode<int>(10)); 
	std::shared_ptr<ListNode<int>> sp2(new ListNode<int>(20));
	sp1->_next = sp2;
	sp2->_prev = sp1;

	std::cout<<sp1.use_count()<<std::endl;
	std::cout<<sp2.use_count()<<std::endl;
}

  那么為什么用weak_ptr就可以解決循環引用的問題,簡單點的來說:weak_ptr的構造和析構不會引起引用計數的增加或減少.

  最后,作為補充:weak_ptr必須與shared_ptr配合使用,不能單獨使用.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM