C++语法学习笔记三十九:shared_ptr使用场景、陷阱、性能分析、使用建议
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                C++语法学习笔记三十九:shared_ptr使用场景、陷阱、性能分析、使用建议
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                實例代碼
// #include <iostream> #include <vector> #include <map> #include <string> #include <memory>using namespace std;shared_ptr<int> create0(int value){return make_shared<int>(value); //返回一個shared_ptr }void myfunc(int value){shared_ptr<int> ptmp = create0(10);return; // 離開作用域后, ptemp會被自動釋放,它所指向的內存也會被自動釋放 }shared_ptr<int> myfunc1(int value){shared_ptr<int> ptmp = create0(10);return ptmp; // 系統是根據ptmp這個局部變量來產生一個臨時的shared_ptr對象往回返 }void proc(shared_ptr<int> ptr){return; }class CT { public:shared_ptr<CT> getself(){return shared_ptr<CT>(this); //用裸指針初始化了多個shared_ptr的感覺;} };class CT1 : enable_shared_from_this<CT1> { public:shared_ptr<CT1> getself(){return shared_from_this(); // 這個就是enable_shared_from_this 類模板} };class CB; //聲明一下CBclass CA{ public:shared_ptr<CB> m_pbs;~CA(){int test;test = 1;} };class CB{ public:shared_ptr<CA> m_pas;~CB(){int test;test = 1;} };class CB1; //聲明一下CBclass CA1{ public:shared_ptr<CB1> m_pbs;~CA1(){int test;test = 1;} };class CB1{ public:weak_ptr<CA1> m_pas; //把這里變成弱引用;~CB1(){int test;test = 1;} };int main() {//一、std::shared_ptr 使用場景//myfunc(12); // 如果這塊不用shared_ptr變量來接收myfunc返回的結果,那么從myfunc返回的shared_ptr就會被銷毀,所指向的對象也會被銷毀。 auto p11 = myfunc1(12); // 我們用了一個變量來接myfunc的返回值,那么myfunc1返回的shared_ptr就不會被銷毀,它所指向的對象也不會被銷毀。//二、std::shared_ptr 使用陷阱分析// (2.1) 慎用裸指針int *p = new int(100); //裸指針//proc(p); //語法錯, int* p 不能轉換成shared_ptr<int>shared_ptr<int> p2(p);proc(p2);proc(shared_ptr<int>(p)); // 參數是個臨時的shared_ptr, 用一個裸指針顯式的構造;*p = 45; // 潛在的不可預料的問題; 因為p指向的內存已經被釋放了;*p2 = 45;//把一個普通裸指針綁定到了一個shared_ptr上之后,那內存管理的責任就交給了shared_ptr了,這個時候你就不應該再//用裸指針(內置指針)來訪問shared_ptr 所指向的內存了;shared_ptr<int> myp(new int(100));proc(myp);*myp = 45;//絕對要記住,不要用裸指針初始化多個shared_ptrint *p1 = new int(100); // 裸指針shared_ptr<int> p3(p1);shared_ptr<int> p4(p1); // p1 和 p4 無關聯了(p3和p4每個強引用計數都為1了),會導致p3和p4所指向的內存被釋放兩次,產生異常shared_ptr<int> p5(new int);shared_ptr<int> p6(p5); // 這種寫法就是ok的,p5和p6 指向同一個內存地址并且兩者是互通(用的是同一個控制塊)// (2.2) 慎用get()返回的指針//返回智能指針指向的對象所對應的裸指針(有些函數接口可能只能使用裸指針)//get返回的指針不能delete,否則會異常shared_ptr<int> myp1(new int(100));int *p00 = myp1.get();//delete p00; // 不可以刪除,會導致異常//不能將其他智能指針綁定到get返回的指針上shared_ptr<int> myp2(new int(100));int *p22 = myp2.get(); //這個指針千萬不能隨意釋放,否則myp2就沒辦法正常管理該指針了{shared_ptr<int> myp3(p22); // 現在myp2和myp3引用計數都為1,但一旦跳出這個程序塊shared_ptr<int> myp4;myp4 = shared_ptr<int>(p22);shared_ptr<int> myp5(myp2);}//離開上邊這個myp3的范圍,導致myp2指向的內存被釋放了;*myp2 = 65; // 該內存已經被釋放,這樣賦值會導致不可預料的后果;//結論:永遠不要用get得到的指針來初始化另外一個智能指針或者給另外一個智能指針賦值。// (2.3) 不要把類對象指針(this) 作為shared_ptr返回,改用enable_shared_from_thisshared_ptr<CT> pct1(new CT);//shared_ptr<CT> pct2 = pct1; //這是兩個強引用;shared_ptr<CT> pct2 = pct1->getself(); //問題出現;//用到C++標準庫里邊的類模板: enable_shared_from_this://現在,在外面創建CT對象的智能指針以及通過CT對象返回的this智能指針都是安全的;//這個enable_shared_from_this中有一個弱指針weak_ptr,這個弱指針能夠監視this,// 在我們調用shared_from_this()這個方法時,這個方法內部實際上是調用了這個weak_ptr的lock()方法;// 大家都知道lock方法會讓shared_ptr指針計數+1, 同時返回這個shared_ptr , 這個就是工作原理;// (2.4) 避免循環引用shared_ptr<CA> pca(new CA);shared_ptr<CB> pcb(new CB);pca->m_pbs = pcb; // 等價于指向CB對象的有兩個強引用pcb->m_pas = pca; // 等價于指向CA對象的有兩個強引用shared_ptr<CA1> pca1(new CA1);shared_ptr<CB1> pcb1(new CB1);pca1->m_pbs = pcb1; // 等價于指向CB1對象的有兩個強引用pcb1->m_pas = pca1; // 因為m_pas 是弱引用,所以這里指向CA1的對象只有一個強引用;// 離開作用域之后,pca引用計數從1 就變成0 會釋放CA1 對象(CA1的析構函數被執行);// CA1 的析構函數被執行了,(表示對象即將被釋放),導致CA1內的m_pbs引用計數會減1, 也就是指向CB1對象的引用計數-1;// 超出pcb作用域時指向CB1 的計數也會-1;最終,會有一個時刻,指向CB1對象的強引用計數會從1減少到0,導致CB1對象被釋放;//CA1先析構,CB1后析構;//三、性能說明// (3.1) 尺寸問題//shared_ptr的尺寸是裸指針的2倍; weak_ptr的尺寸是裸指針的2倍;char *p111;int ilenp111 = sizeof(p111); // 4字節shared_ptr<string> p222;int ilenp222 = sizeof(p222); // 8字節 ,包含兩個裸指針的//a). 第一個裸指針指向的是這個智能指針所指向的對象//b). 第二個裸指針 指向一個很大的數據結構(控制塊),這個控制塊里邊有啥://b.1) 所指向對象的強引用計數: shared_ptr//b.2) 所指向對象的弱引用計數: weak_ptr//b.3) 其他數據,比如刪除器指針,內存分配器;// 這個控制塊是由第一個指向某個對象的shared_ptr來創建的;//控制塊創建時機:// a) make_shared : 分配并初始化一個對象,返回指向此對象的shared_ptr,所以,這個make_shared它總是能夠創建一個控制塊shared_ptr<int> p333 = make_shared<int>(100);// b) 用裸指針來創建一個shared_ptr 對象時,int *pi111 = new int();shared_ptr<int> p555(pi111);shared_ptr<int> p666(pi111); // 不允許,否則會產生多個控制塊,也就是多個引用計數(每個都是1)析構時析構多次,導致異常;shared_ptr<int> p777(new int);// (3.2) 移動語義shared_ptr<int> p888(new int(100));shared_ptr<int> p999(std::move(p888)); //移動語義, 移動構造一個新的智能指針對象p2,// p1 就不再指向該對象(變成空),引用計數依舊是1;shared_ptr<int> p1000; p1000 = std::move(p999); // 移動賦值, p999指向空,p1000指向該對象,整個對象引用計數仍舊為1;//移動肯定比復制快,復制你要增加引用計數,移動不需要;//移動構造函數快過復制構造函數,移動賦值運算符快過拷貝賦值運算符;//四、 補充說明和使用建議// a). 掌握了絕大部分shared_ptr用法;小部分沒講解,靠大家摸索。// 分配器,解決內存分配問題;// shared_ptr<int> p(new int), mydeleter(), mymallocator<int>()); ....// b). 謹慎使用,凡是沒講到過的用法:// new shared_ptr<T> , memcpy() 奇怪用法,大家不要輕易嘗試。// c). 優先使用make_shared()shared_ptr<string> ps1(new string("I Love China!")); // 分配兩次內存auto ps2 = make_shared<string>("I Love China!");// 分配1次內存system("pause"); }總結
以上是生活随笔為你收集整理的C++语法学习笔记三十九:shared_ptr使用场景、陷阱、性能分析、使用建议的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: TCP的request_sock与soc
 - 下一篇: CHD的impala实现hive和hba