智能指針作用:
一般的指針,存在資源泄露的問題。而智能指針一定會保證資源自動釋放(會自動調用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();
}