日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++总结8——shared_ptr和weak_ptr智能指针

發布時間:2023/11/30 c/c++ 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++总结8——shared_ptr和weak_ptr智能指针 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://blog.csdn.net/wendy_keeping/article/details/75268687

智能指針的提出:智能指針是存儲指向動態分配對象指針的類,用于生存期控制。能夠確保正確銷毀動態分配的內存,防止內存泄露。

1.智能指針的分類:?
不帶引用計數的智能指針?
auto_ptr unique_ptr scoped_ptr

帶引用計數的智能指針?
shared_ptr:強智能指針?
weak_ptr:若智能指針

2.不帶引用計數的智能指針是如何確保正確釋放堆上內存的??
auto_ptr:

auto_ptr<A> ptr1(new A(10)); auto_ptr<A> ptr2 = ptr1;
  • 1
  • 2

當這兩行代碼執行完后,ptr1已經不再指向A這個對象,并且ptr1=NULL,ptr1對A對象的所有權已經轉移給了ptr2,也就不能通過ptr1調用該類的方法。

vector<auto_ptr<int>> vec;

不能將auto_ptr類型的指針作為STL容器的元素。因為容器避免不了直接拷貝構造和互相賦值。auto_ptr的這種特性會給STL容器的使用造成很大的麻煩。

unique_ptr:

unique_ptr<A> ptr1(new A(10)); unique_ptr<A> ptr2 = ptr1;//error unique_ptr<A> ptr3 = func();//ok

unique_ptr不支持拷貝構造函數和賦值運算符重載函數,不能隱式的將原指針置為NULL,但是可以通過返回值賦值。unique_ptr支持移動構造函數和移動賦值運算符重載函數,是通過move(C++11標準)函數實現的,用戶明確知道對象的所有權已經發生轉移,不能再使用原來的指針調用類的方法。這也是auto_ptr和unique_ptr最根本的區別。

scoped_ptr:

scoped_ptr不支持所有權的轉移,只能通過該指針對對象進行操作,出作用域會自動析構。

3.帶引用計數的智能指針

shared_ptr<A> pa(new A()); shared_ptr<A> pb = pa;

當使用指針指向堆上的對象時,該對象的引用計數加1??截悩嬙旎蛸x值時,不產生該對象的副本,只是更改對象的引用計數。如果別的智能指針也指向這個對象時,也是增加其引用計數。如果delete 指針時,先對引用計數減1,直到對象的引用計數減為0,才調用該對象的析構函數。

4.智能指針的交叉引用導致內存泄露

class A { public:shared_ptr<B> _pb; }; class B { public:shared_ptr<A> _pa; };int main() {shared_ptr<A> pa(new A());shared_ptr<B> pb(new B());pa->_pb = pb;pb->_pa = pa;return 0; }

pa指針指向堆上對象后,A的引用計數是1,B的引用計數是1。?
pa->_pb = pb;此時,B的引用計數是2。?
pb->_pa = pa;此時,A的引用計數是2。

出作用域后:?
pb指針釋放,B對象的引用計數減1,此時,B的引用計數是1,并不調用B的析構函數。?
pa指針釋放,A對象的引用計數減1,此時,A的引用計數是1,并不調用A的析構函數。

程序運行結束,A和B對象并未析構,造成內存泄露

為了避免內存泄露,必須打斷這種循環等待的現象。智能指針提供了weak_ptr(弱智能指針)可以避免產生循環等待的現象。

weak_ptr,當用weak_ptr指向對象時,對象的引用計數并不加1,因為弱智能指針沒有對對象的使用權,它只有監控權。

#include <iostream> #include <memory> using namespace std;class A { public:weak_ptr<B> _pb; }; class B { public:shared_ptr<A> _pa; };int main() {shared_ptr<A> pa(new A());shared_ptr<B> pb(new B());pa->_pb = pb;pb->_pa = pa;return 0; }

pa指針指向堆上對象后,A的引用計數是1,B的引用計數是1。?
pa->_pb = pb;此時,B的引用計數是1。因為A的成員對象是weak_ptr。?
pb->_pa = pa;此時,A的引用計數是2。

出作用域后:?
pb指針釋放,B對象的引用計數減1,此時,B的引用計數是0,調用B的析構函數,先析構自己(B被析構),再析構成員對象(A的引用計數減1,此時A的引用計數是1)?
pa指針釋放,A對象的引用計數減1,此時,A的引用計數是0,調用A的析構函數(A被析構)

為了避免智能指針循環引用造成的內存泄露情況,要遵守:創建對象的時候,一定要用強智能指針,其他地方只能用持有資源的弱智能指針。

智能指針本身是線程安全的。使用atomic_increment和atimic_decreament進行對多線程間的互斥,保證引用計數count++/count–是原子操作。

5.多線程訪問共享的C++對象產生的線程安全的問題

#include <iostream> #include <memory> using namespace std;class C { public:C(){}~C(){}void func(){cout<<"call func()"<<endl;} };void* threadProc(void *lparg) {shared_ptr<C> pc = (shared_ptr<C>)lparg;pc->func();//如果對象已經析構,則程序崩潰!return NULL; }int main(int argc, char* argv[]) {shared_ptr<C> c(new C());pthread_t tid;pthread_create(&tid, NULL, threadProc, &c);return 0; }

多線程中可能訪問共享的對象,如果對象已經析構,線程中訪問它,程序會崩潰掉。解決多線程訪問共享的C++對象產生的線程安全的問題,可以使用weak_ptr。將弱智能指針轉給線程,再訪問對象時,先將弱智能和提升為強智能指針,如果提升成功,則說明對象還存在,可以訪問該對象的成員變量或方法。如果提升失敗,則說明對象已經析構。

#include <iostream> #include <memory> using namespace std;class C { public:C(){}~C(){}void func(){cout<<"call func()"<<endl;} };void* threadProc(void *lparg) {weak_ptr<C> pw = *(weak_ptr<C>*)lparg;shared_ptr<C> pc = pw.lock(); //類型提升if(pc != NULL) //類型提升成功,對象未析構{pc->func();}return NULL; }int main(int argc, char* argv[]) {shared_ptr<C> c(new C());pthread_t tid;weak_ptr<C> pw(c);pthread_create(&tid, NULL, threadProc, &pw);return 0; }

創建對象的時候一定要用強智能指針,其他地方只能用持有資源的弱智能指針!!!


總結

以上是生活随笔為你收集整理的C++总结8——shared_ptr和weak_ptr智能指针的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。