- 頭文件memory
shared_ptr類
- 允許多個指針指向同一個對象;
創建和初始化
shared_ptr<string> p1;
shared_ptr<int> p2 = make_shared<int>(42);
shared_ptr<string> p3 = make_shared<string>(10,'9');
shared_ptr<int> p4 = make_shared<int>();//值初始化
auto p5 = make_shared<vector<string>>();
拷貝和賦值
- 拷貝:遞增計數器
auto p = make_shared<int>(42);
auto q(p);
- 賦值:遞減等號左邊的計數器,遞增等號右邊的計數器
auto r = make_shared<int>(42);
r = q;//遞減r指向對象的引用計數,遞增q指向對象的引用計數
- 當指向一個對象的最後一個shared_ptr被銷燬時,shared_ptr會自動銷燬指向的對象,並釋放相關聯的內存。
其他操作
-
*p
-
p.get()
:返回內置指針; -
swap(p,q)
:交換指針; -
p.use_count()
:返回與p共享對象的智能指針數量; -
p.unique()
:如果use_count返回1,則返回true,否則返回false; -
p.reset()
:若p是唯一指向其對象的shared_ptr,則釋放此對象;如果不是,就把p置空; -
p.reset(q)
:若p是唯一指向其對象的shared_ptr,則釋放此對象;令p指向q;shared_ptr<int> p(new int(1024));//正確,使用普通指針初始化智能指針 p = new int(2048); //錯誤,普通指針不能轉化爲智能指針 p.reset(new int(2048));//正確,p指向一個新對象,並釋放原有對象(因爲p是唯一指向原對象的智能指針)
shared_ptr<int> p1(new int(1024)); shared_ptr<int> p2(p1); p1.reset(new int(2048));//此時p1指向2048,而p2指向1024
-
reset()
經常與unique()
一起使用,來控制多個shared_ptr共享的對象:if(!p.unique()) p.reset(new string(*p)); //如果p不是獨有該對象,則先製作一份拷貝,使得p指向拷貝的對象 *p+=newVal; //在拷貝對象上進行操作,不會影響其他共享的智能指針
unique_ptr類
- 某個時刻只能有一個unique_ptr指向一個給定對象;
不支持拷貝和賦值!
unique_ptr<int> p1=new int(1024); //錯誤!!不能轉換
unique_ptr<int> p1(new int(1024)); //正確!!
unique_ptr<int> p2(p1); //錯誤!!不能拷貝
unique_ptr<int> p2=p1; //錯誤!!不能賦值
- 函數的實參傳遞和返回值也是拷貝,但是由於返回值拷貝之後,原unique_ptr會被銷燬,因此返回一個unique_ptr是正確的,但是實參傳遞不支持拷貝。
操作:
up.get()
:返回內置指針;up.release()
:up置空,返回普通指針,但是不釋放up指向的對象;up.reset()
:釋放up指向的對象;up置空;up.reset(q)
:釋放up指向的對象(因爲up是唯一的指針);令up指向q(新對象);- 通過調用
release()
和reset()
實現“拷貝和賦值”:
unique_ptr<int> p1(new int(1024));// p1->1024
unique_ptr<int> p2(p1.release()); //將對象的所有權從p1轉到p2; p2->1024,p1->NULL
unique_ptr<int> p3(new int(2048)); // p3->2048
p2.reset(p3.release());//釋放p2指向的對象,然後p2指向p3 p2->2048, p3->NULL
p2.reset(new int(4096)); // p2->4096
weak_ptr類
- 指向一個由shared_ptr管理的對象,一旦最後一個指向對象的shared_ptr被銷燬,對象就會被釋放,即使有weak_ptr指向該對象。
初始化
- 只能用shared_ptr來初始化weak_ptr:
auto p=make_shared<int>(42);
weak_ptr<int> wp(p); //p指向的對象的計數不會增加
拷貝和賦值
shared_ptr<int> p=make_shared<int>(42);
weak_ptr<int> wp=p; //可以將shared_ptr轉化爲weak_ptr;
操作:
-
wp.reset()
:wp置空; -
wp.use_count()
:返回與wp共享的shared_ptr的數量; -
wp.expired()
:如果use_count()爲0,返回true,否則返回false; -
wp.lock()
:如果expired()爲true,返回空shared_ptr指針,否則返回一個指向wp對象的shared_ptr; -
由於weak_ptr指向的對象可能不存在,因此不能使用weak_ptr直接訪問對象:
if(shared_ptr<int> np=wp.lock()){*np++}
weak_ptr的作用
-
weak_ptr 設計的目的是爲配合 shared_ptr 而引入的一種智能指針來協助 shared_ptr 工作, 它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構造, 它的構造和析構不會引起引用記數的增加或減少。weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,如果說兩個shared_ptr相互引用,那麼這兩個指針的引用計數永遠不可能下降爲0,資源永遠不會釋放。
class B; class A{ public: shared_ptr<B> pb_; ~A(){cout<<"A delete\n";} }; class B{ public: shared_ptr<A> pa_; ~B(){cout<<"B delete\n";} }; void fun(){ shared_ptr<B> pb(new B()); shared_ptr<A> pa(new A()); pb->pa_ = pa; pa->pb_ = pb; cout<<pb.use_count()<<endl; cout<<pa.use_count()<<endl; } int main(){ fun(); return 0; }
- 這種情況下,指向對象A和對象 B指針計數都是2,當退出函數fun()之後,引用計數分別減1,這樣對象A和對象B的引用計數都變成1,無法釋放內存;
- 如果將其中一個shared_ptr改爲weak_ptr,由於weak_ptr不改變對象的引用計數,所以fun()執行時的引用計數分別爲2和1,退出fun()之後,分別遞減成1和0,導致B對象被釋放,釋放B的同時也會讓A的計數減1,這樣AB可以全部被釋放;