5-5 shared_ptr使用場景、陷阱、性能分析、使用建議

005shared_ptr常用操作與使用陷阱

#include<iostream>
#include<cstdlib>
#include<string>
#include<vector>
#include <memory>

using namespace std;

//測試類
class CT:public enable_shared_from_this<CT>
{
public:
	shared_ptr<CT>getself()
	{
		//return shared_ptr<CT>(this);
		return shared_from_this();//enable_shared_from_this類中的方法
	}
};

class B;//聲明B類
class A
{
public:
	
	shared_ptr<B> pm_b;
	//解決辦法:
	//weak_ptr<B>pm_b''
	~A()
	{
		cout << "A的析構函數" << endl;
	}
};


class B
{
public:
	shared_ptr<A> pm_a;
	~B()
	{
		cout << "B的析構函數" << endl;
	}
};
//A類和B類循環引用

shared_ptr<int>createFunction(int value)
{
	return make_shared<int>(value);//返回一個shared_ptr指針
}
//
//void myFunction(int value)
//{
//	shared_ptr<int>pTem = createFunction(100);
//	return;//離開作用域後,pTem所指向的內存會被自動釋放
//}


shared_ptr<int> myFunction(int value)
{
	shared_ptr<int>pTem = createFunction(100);
	return pTem;//返回局部對象
}


void myFuncion02(shared_ptr<int>ptr)
{
	return;
}

int main(void)
{
	//(1)
	myFunction(100);
	shared_ptr<int>p1 = myFunction(10);//如果不用變量來接受,返回的局部變量就會銷燬。


	//2.1慎用裸指針
	int*p = new int(100);
	//myFuncion02(p);//error,不允許隱式類型轉化
	myFuncion02(shared_ptr<int>(p));//參數是臨時的shared_ptr,用一個裸指針顯式的構造
	*p = 22;//這一段內存已經被回收,臨時對象傳遞給函數會是個局部量,函數運行完畢會釋放。
	//內存對象的管理已經交給智能指針,這裏不要再使用裸指針

	//不要使用裸指針初始化多個shared_ptr--會導致內存釋放多次 p3,p4無關
	/*int*p2 = new int(200);
	shared_ptr<int>p3(p2);
	shared_ptr<int>p4(p2);*/
	//更改方法:
	shared_ptr<int>p3(new int(200));
	shared_ptr<int>p4(p3);//這種寫法是ok的,用的是同一個控制塊,指向同一塊內存塊
	
	//2.2慎用get()函數的返回值--返回指正對象指針的裸指針,不能刪除
	shared_ptr<int>p5(new int(234));
	int *p6 = p5.get();
	//delete p;
	//不可以將其他智能指針綁定到get返回的裸指針上
	//shared_ptr<int>p7(p6);//兩個智能指針沒有關係,當一個釋放的時候,另一個再釋放一次就會出錯
	//每個智能指針用裸指針創建,他們之間的引用是相互分離的。

	//3.不要把類對象指針(this)作爲shared_ptr返回,改用enable_shared_from_this返回
	shared_ptr<CT>Pct1(new CT);
	//shared_ptr<CT>Pct2(Pct1);//兩個強引用,使用同一個控制塊
	shared_ptr<CT>pct3 = Pct1->getself();//兩個智能指針之間不是使用同一個控制塊,沒有關係.有一種使用裸指針初始化智能指針的
	//解決辦法:c++標準庫中的類模板enalbe_shared_from_this,返回的是一個智能指針


	//2.4避免循環引用
	shared_ptr<A> pca(new A);
	shared_ptr<B> pcb(new B);
	pca->pm_b = pcb;//指向pcb的有兩個強引用
	pcb->pm_a = pca;//指向pca的有兩個強引用
	/*
	 * 最終所有的內存都沒有釋放,因爲對象互相包含對象,每個對象的強引用都是2,都不能釋放。
	 * 解決辦法:
	 *	只需要將其中一個變爲弱引用即可。
	 */

	//3.2移動語義
	shared_ptr<int>p7(new int(1000));
	shared_ptr<int>p8(std::move(p1));//移動構造,移動構造一個新的智能指針對象p8,p7不再指向1000,
	//引用計數還是1

	//43.優先使用make_shared,編譯器有優化這個函數。
	shared_ptr<string>p9(new string("jisuan"));
	/*
	 * 分配兩次內存,一次存儲jisuan,一次用來存放p9的控制塊
	 */
	auto p10 = make_shared<string>("jisuajis");//只分配一次內存
	system("pause");
	return 0;
}

/*
*(1)shared_ptr使用場景-
*	從函數中return shared_ptr類型指針
*	
*
*(2)智能指針是用錯誤分析
*	2.1慎用裸指針--使用裸指針賦值給智能指針後,內存管理的責任就交給智能指針,就不應該再使用裸指針訪問內存了。
*		不用使用裸指針初始化多個shared_ptr
*	2.2慎用get()函數的返回值
*	返回智能對象的裸指針不能delete,否則會異常
*	永遠不要用get()得到的裸指針來初始化另一個智能指針。
*	3.不要把類對象指針(this)作爲shared_ptr返回,改用enable_shared_from_this返回
*		返回對象的this指針,使用public繼承enable_shared_from_this<>,然後返回shared_from_this()
*	原理:enable_shared_from_this中有一個弱指針weak_ptr,通過這個弱指針監視this指針。
*	在我們調用shared_from_this()方法的時候,這個方法內部調用了weak_ptr的lock()方法,返回shared_ptr指針計數—+1
*	並返回shared_ptr指針
*	2.4避免循環引用
*		
*(3)性能說明
*3.1尺寸問題
*	shared_ptr,weak_ptr的尺寸都是裸指針的2倍。
*	創建控制塊的時機:
*	1.make_shared,分配並初始化一個對象,返回指向此對象的shared_ptr
*	2.用裸指針來創建愛女一個shared_ptr對象時候,使用裸指針會產生多個控制塊,詳見2.2
*	
*3.2移動語義
*移動肯定比賦值塊,複製要增加引用計數,但是移動不會增加引用計數。
*
*(4)補充說明和使用建議
*	1.分配器等問題沒有講解。
*	2.智能指針也不是刻意隨心所欲的使用,謹慎使用。
*	3.優先使用make_shared,編譯器有優化這個函數。
*
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章