C++:10.智能指針

智能指針作用:

一般的指針,存在資源泄露的問題。而智能指針一定會保證資源自動釋放(會自動調用delete),不用用戶參與。

爲什麼會自動調用delete?

實際上智能指針也是用類定義的,利用棧上的指針出函數就會自動調用析構函數的特點。

所以不能使用堆上的指針,因爲出函數不會析構。也不要定義全局的,因爲程序結束自己就釋放了。

頭文件:#include <memory>


1、帶引用計數的智能指針。

1)shared_ptr   強智能指針  可以改變資源的引用計數。 會出現循環引用的問題。

如果多個shared_ptr指向了同一塊資源。該資源的引用計數就每次加1。如果不指向了就減1。當引用計數爲0時,就會自動釋放該資源。

shared_ptr內部的引用計數是線程安全的,但是對象的讀取需要加鎖。

初始化方式:智能指針是個類,並不是一個指針(雖然它的成員變量是個指針)。所以不能將一個指針直接賦值給智能指針。也就是說:shared_ptr<int> pra = new int; 這種寫法是錯的。而是應該shared_ptr<int> pra(new int);

2)weak_ptr      弱智能指針  不會改變資源的引用計數。

弱智能指針不能直接訪問對象,但如果提升爲強智能指針(引用計數+1)就可以訪問,用lock()方法。前提資源還存在,引用計數不爲0。如果資源沒了,當然指向NULL。出局部析構-1;

多線程也是安全的,不會出現剛提升,就有其他線程析構了。因爲+1了,+1是上了鎖的。

弱智能指針可以直接接受強智能指針.

弱智針是不可以使用->來訪問對象的。需要將弱智針提升爲強指針。shared_ptr<A> ptra = _ptra.lock();  // 提升

shared_ptr和weak_ptr的使用建議:

結論:創建對象的地方使用強智能指針,其它地方一律使用弱智能指針。

2、不帶引用計數的智能指針。

1、auto_ptr

在C++標準提供了auto_ptr。這個智能指針不支持拷貝構造函數。當想ptr2(ptr1); 會將ptr1置爲NULL,ptr2指向ptr1之前的地址。所以禁止使用C++標準可提供的auto_ptr

可以任意轉移資源的所有權,但用戶無法感知。

2、scope_ptr

 禁止拷貝構造與賦值。方式是私有的。不能任意轉化所有權。

3、unique_ptr

同一時刻只能有一個unique_ptr指向給定的對象。不能賦值,不能拷貝。但用戶可以調用函數(move)還轉換所有權。

遺留問題:1、拷貝構造和賦值不能在同一個作用域下使用,但可以在一個函數返回時調用。
                             2、不是所有資源都是使用delete 那麼怎麼定義刪除器。

unique_ptr<int> getUniquePtr_1()
{
	unique_ptr<int> p(new int);
	return p;   返回局部變量,C++優化規則.
}
unique_ptr<int> getUniquePtr_2()
{
    return unique_ptr<int> (new int);返回臨時量
}

int main()
{

	unique_ptr<int> p1(new int);
	unique_ptr<int> p2(p1);   拷貝構造報錯
	p2 = p1;                  賦值重載報錯

	unique_ptr<int> p3 = getUniquePtr_1();正確,直接拷貝構造p3.
}

在unique_ptr中拷貝構造與賦值重載是放在public中的,通過在後面加=delete。從而達到刪除該函數的目的,導致無法使用。
但其實還提供了右值引用(C++11)的拷貝構造與賦值重載。在這裏調用的就是右值引用的函數。

智能指針的循環引用(交叉引用)問題:

解決方法:創建對象的地方使用強智能指針,其它地方一律使用弱智能指針。也就是說在類中的指針使用弱指針即可。

原因:弱指針引用計數不會加一。


一個將弱智針提升爲強指針的例子:

class B;
class A
{
public:
	A(){ cout << "A()" << endl; }
	~A(){ cout << "~A()" << endl; }
	void func(){ cout << "call A::func" << endl; }
	weak_ptr<B> _ptrb;
};
class B
{
public:
	B(){ cout << "B()" << endl; }
	~B(){ cout << "~B()" << endl; }
	void test()
	{
		// 想通過_ptra訪問A對象的func方法,調用一下
		shared_ptr<A> ptra = _ptra.lock();  // 提升
		if (ptra != NULL) // 提升成功,調用func方法
		{
			ptra->func();
		}
	}
	weak_ptr<A> _ptra; // operator-> 不允許通過weak_ptr訪問對象
};

int main()
{
	shared_ptr<A> ptra(new A());
	shared_ptr<B> ptrb(new B());
	ptra->_ptrb = ptrb;
	ptrb->_ptra = ptra;

	ptrb->test();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章