c++——智能指針學習(shared_ptr和weak_ptr)


 先看一個例子:Stark和Targaryen家族你中有我,我中有你。我們設計以下類企圖避免內存泄漏,使得析構函數都能調用到:

#include<iostream>
#include<memory>
using namespace std;

class Stark;
class Targaryen;

class Stark
{
	private:
	  Targaryen *targaryen;

	public:
		void prin(){cout<<"stark love targaryen"<<endl;}
		~Stark()
		{
			delete targaryen;
			cout<<"~Stark"<<endl;
		}
};

class Targaryen
{
  private:
	Stark *stark;

  public:
	void prin() { cout << "targaryen love stark" << endl; }
	~Targaryen()
	{
		delete stark;
		cout << "~Targaryen" << endl;
	}
};

int main()
{
	Targaryen *tar    = new Targaryen;
	Stark     *stark  = new Stark;

	delete stark;

	system("pause");
	return 0;
} 

 打印結果:

正常來說,我們要求的結果是兩個對象都要析構掉,但是我們可以debug執行看到,並沒有全部析構,顯然不是我們的需求!

那么換一種智能指針的寫法,看看結果怎么樣:

class Stark;
class Targaryen;

class Stark
{
	private:
	  //Targaryen *targaryen;
	shared_ptr<Targaryen> share_tar;
	public:
		void prin(){cout<<"stark love targaryen"<<endl;}
		void setTargaryen(shared_ptr<Targaryen> tar)
		{
			this->share_tar = tar;
		}
		~Stark()
		{
			//delete targaryen;
			cout<<"~Stark"<<endl;
		}
};

class Targaryen
{
  private:
	//Stark *stark;
	shared_ptr<Stark> share_stark;
	//weak_ptr<Stark> weak_stark;

  public:
	void prin() { cout << "targaryen love stark" << endl; }
	void setStark(shared_ptr<Stark> stark)
	{
		this->share_stark = stark;
	}
	~Targaryen()
	{
		//delete stark;
		cout << "~Targaryen" << endl;
	}
};

int main()
{
	weak_ptr<Stark> wpstark;
	weak_ptr<Targaryen> wptar;

	//Targaryen *tar    = new Targaryen;
	//Stark     *stark  = new Stark;
	{
	shared_ptr<Targaryen> tar(new Targaryen);
	shared_ptr<Stark> stark(new Stark);
	tar->prin();
	stark->prin();
	tar->setStark(stark);
	stark->setTargaryen(tar);
	wpstark = stark;
	wptar = tar;
	cout << tar.use_count() << endl;
	cout << stark.use_count() << endl;
	}

	cout << wpstark.use_count() << endl;
	cout << wptar.use_count() << endl;

	//delete stark;

	system("pause");
	return 0;
} 

 我們希望在main中第一對{}號結束的時候,打印析構函數,但是並沒有

那我們再換一種寫法:

 

class Stark;
class Targaryen;

class Stark
{
	private:
	  //Targaryen *targaryen;
	shared_ptr<Targaryen> share_tar;
	public:
		void prin(){cout<<"stark love targaryen"<<endl;}
		void setTargaryen(shared_ptr<Targaryen> tar)
		{
			this->share_tar = tar;
		}
		~Stark()
		{
			//delete targaryen;
			cout<<"~Stark"<<endl;
		}
};

class Targaryen
{
  private:
	//Stark *stark;
	//shared_ptr<Stark> share_stark; ////這里變了~~~~~~~~~~~~
	weak_ptr<Stark> weak_stark;

  public:
	void prin() { cout << "targaryen love stark" << endl; }
	void setStark(shared_ptr<Stark> stark)
	{
		this->weak_stark = stark;
	}
	~Targaryen()
	{
		//delete stark;
		cout << "~Targaryen" << endl;
	}
};

 這次結果還是令人滿意的。

那么問題來了,為什么要這么做呢?為什么要用weak_ptr取代shared_ptr呢?

我們看weak_ptr的官方定義:

std::weak_ptr 是一種智能指針,它對被 std::shared_ptr 管理的對象存在非擁有性(“弱”)引用。在訪問所引用的對象前必須先轉換為 std::shared_ptr

std::weak_ptr 用來表達臨時所有權的概念:當某個對象只有存在時才需要被訪問,而且隨時可能被他人刪除時,可以使用 std::weak_ptr 來跟蹤該對象。需要獲得臨時所有權時,則將其轉換為 std::shared_ptr,此時如果原來的 std::shared_ptr 被銷毀,則該對象的生命期將被延長至這個臨時的 std::shared_ptr 同樣被銷毀為止。

std::weak_ptr 的另一用法是打斷 std::shared_ptr 所管理的對象組成的環狀引用。若這種環被孤立(例如無指向環中的外部共享指針),則 shared_ptr 引用計數無法抵達零,而內存被泄露。能令環中的指針之一為弱指針以避免此情況。

這種就是一種環狀的情況。

另外,還有一點要注意:

 1 int main()
 2 {
 3     {
 4         int *a = new int;
 5         std::shared_ptr<int> p1(a);
 6         std::shared_ptr<int> p2(a);
 7     }
 8     system("pause");
 9     return 0;
10 }

這樣寫會報錯。因為,析構的時候,指針a會被delete兩次。因此,為了避免這種情況的發生,我們盡可能不適用new來初始化shared_ptr。而是用make_shared;

 1 class Mars
 2 {
 3   public:
 4     Mars ()
 5     {
 6         cout << this << ": Mars" << endl;
 7     }
 8     ~Mars()
 9     {
10         cout << this << ": ~Mars" << endl;
11     }
12 };
13 int main()
14 {
15     {
16         Mars pMars;
17         shared_ptr<Mars> p1 = make_shared<Mars >(pMars);
18         shared_ptr<Mars> p2 = make_shared<Mars >(pMars);
19     }
20     system("pause");
21     return 0;
22 }

這玩意兒太復雜了~只是清楚大概是干什么的。但是還不會用……以及什么時候用,關鍵是我們這公司平時也不用,這就尷尬了。

用shared_ptr,不用new
使用weak_ptr來打破循環引用
用make_shared來生成shared_ptr
用enable_shared_from_this來使一個類能獲取自身的shared_ptr

結束!以后有時間再慢慢研究。

 

大部分都是抄的:

https://zh.cppreference.com/w/cpp/memory/shared_ptr

https://www.cnblogs.com/wxquare/p/4759020.html

https://blog.csdn.net/worldwindjp/article/details/18843087

https://heleifz.github.io/14696398760857.html

 


免責聲明!

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



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