NDK14_C++基礎:智能指針

NDK開發彙總

自C++11起,C++標準庫提供了兩大類型的智能指針

一 shared_ptr

操作引用計數實現共享式擁有的概念。多個智能指針可以指向相同的對象,這個對象和其相關資源會在最後一個被銷燬時釋放。

class A {
public:
	~A() {
		cout << "釋放A" << endl;
	}
};

void test() {
	//自動釋放 引用計數爲1
	shared_ptr<A> a(new A());
    //退出方法 shared_ptr a本身釋放,對內部的 A 對象引用計數減1 則爲0 釋放new 出來的A 對象 
}

雖然使用shared_ptr能夠非常方便的爲我們自動釋放對象,但是還是會出現一些問題。最典型的就是循環引用問題。

class B;
class A {
public:
	~A() {
		cout << "釋放A" << endl;
	}
	shared_ptr<B> b;
};

class B {
public:
	~B() {
		cout << "釋放B" << endl;
	}
	shared_ptr<A> a;
};
void test() {
	//自動釋放
	shared_ptr<A> a(new A()); //A引用計數爲1
	shared_ptr<B> b(new B()); //B引用計數爲1
    cout << a.use_count() << endl; //查看內部對象引用計數
	a->b = b;			//A 引用計數爲2
	b->a = a;			//B 引用計數爲2
	//退出方法,a釋放,A引用計數-1結果爲1 不會釋放 B也一樣
}

weak_ptr

weak_ptr是爲配合shared_ptr而引入的一種智能指針。主要用於觀測資源的引用情況。

它的構造和析構不會引起引用記數的增加或減少。沒有重載*和->但可以使用lock獲得一個可用的shared_ptr對象。

配合shared_ptr解決循環引用問題

class B;
class A {
public:
	~A() {
		cout << "釋放A" << endl;
	}
	weak_ptr<B> b;
};
class B {
public:
	~B() {
		cout << "釋放B" << endl;
	}
	weak_ptr<A> a;
};

void test() {
	//自動釋放
	shared_ptr<A> a(new A()); //A引用計數爲1
	shared_ptr<B> b(new B()); //B引用計數爲1

	a->b = b;			//weak_ptr 引用計數不增加
	b->a = a;			//weak_ptr 引用計數不增加
	//退出方法,A B釋放
}

weak_ptr 提供expired 方法等價於 use_count == 0,當expired爲true時,lock返回一個存儲空指針的shared_ptr

二 unique_ptr

實現獨佔式引用,保證同一時間只有一個智能指針指向內部對象。

unique_ptr<A> a(new A());

auto_ptr已經不推薦使用

三 自定義智能指針

template <typename T>
class Ptr {
public:
	Ptr() {
		count = new int(1);
		t = 0;
	}
	Ptr(T *t):t(t) {
		//引用計數爲1
		count = new int(1);
	}
	~Ptr() {
		//引用計數-1 爲0表示可以釋放T了
		if (--(*count) == 0)
		{
			if (t) {
				delete t;
			}
			delete count;
			t = 0;
			count = 0;
		}
	}
	//拷貝構造函數
	Ptr(const Ptr<T> &p) {
		//引用計數+1
		++(*p.count);
		t = p.t;
		count = p.count;
	}

	Ptr<T>& operator=(const Ptr<T>& p) {
		++(*p.count);
		//檢查老的數據是否需要刪除
		if (--(*count) == 0) {
			if (t) {
				delete t;
			}
			delete count;
		}
		t = p.t;
		count = p.count;
		return *this;
	}
	//重載-> 操作T 類
	T* operator->() { return t; }

private:
	T *t;
	int *count;
};

重載=爲什麼返回引用,而不是對象?

return *this後馬上就調用拷貝構造函數,將*this拷貝給一個匿名臨時對象,然後在把臨時對象拷貝給外部的左值(a=b,a爲左值),再釋放臨時對象。這樣首先會造成不必要的開銷。

同時如果沒有自定義的拷貝函數,則會使用默認的淺拷貝。如果類中存在指向堆空間的成員指針,需要進行深拷貝(重新申請內存),避免相同內存地址被其他地方釋放導致的問題。

如果此處返回對象不會導致出現問題:

引用類型(Test1&) 沒有複製對象 返回的是 t 對象本身 t會被釋放 所以會出現問題(數據釋放不徹底就不一定)

這裏的t作用域是函數內我們自己創建的一個臨時對象,因此會被釋放,而在此處返回 *this,作用範圍和t不一樣。其次,在類中定義了拷貝函數,雖然未進行深拷貝,但小心的維護了堆內存指針(t、count),不會出現堆內存釋放導致的懸空指針情況。

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