// 智能指針會自動釋放所指向的對象。 // shared_ptr的應用場景是:程序須要在多個對象間共享數據 /* 先從應用場景入手吧,說礦工A發現了一個金礦。 * 而後礦工A喊來了礦工B,一塊兒開採,不久後礦工A勞累過分死了。 * 礦工B繼續開採着礦工A發現的金礦。 * 可是礦工B不久後得了塵肺病。 * 這時候若是礦工B喊來了礦工C,那礦工C就繼續開採這個金礦, * 若是礦工B至死都沒有喊anyone,那麼這個金礦再也不被任何人發現。 * * 咱們來講說實現 * 每一個礦工new一個對象,金礦new一個對象。 * 礦工死了就delte掉,金礦再也不被發現也delte掉。 * * 可是咱們有沒有可能讓最後一個礦工死時,金礦被自動delte掉? * 這樣的話咱們就不須要額外管理金礦對象了。 * 有可能啊,你用共享指針啊。 * 共享指針管理一個對象,管理一個引用計數。 * 每次對共享指針賦值和拷貝時,引用計數就加1。 * 當共享指針被銷燬時,引用計數就減1。 * 這樣就變成多個礦工間共享金礦數據了。 * * 下面咱們來講說引用計數遞增的狀況 * 1 用一個shared_ptr初始化另外一個shared_ptr,確定調用拷貝構造函數嘍 * 2 用一個shared_ptr賦值另外一個shared_ptr,確定調用賦值函數嘍 * 3 將shared_ptr做爲參數傳遞給一個函數,這個也會調用拷貝構造函數 * 4 將shared_ptr做爲函數的返回值,這個也會調用拷貝構造函數 * * 下面咱們來講說引用計數遞減的狀況 * 1 shared_ptr被銷燬,參數出棧是被銷燬的一種狀況 * 2 給shared_ptr從新賦值 * * 一旦一個shared_ptr的引用計數變爲0,它就會自動釋放所管理的對象。 */ #include <iostream> #include <memory> using namespace std; struct Gold { ~Gold() {total = -1;} int total{20}; Gold &operator--() { --total; return *this; } const Gold operator--(int) { Gold tmp = *this; --(*this); return Gold(tmp); } }; class Miner { public: Miner() : gold(make_shared<Gold>()) {} Miner(const Miner &miner) { gold = miner.gold; } void dig() { (*gold)--; } Gold *base() { return gold.get(); } private: shared_ptr<Gold> gold; }; int main(int argc, char *argv[]) { auto miner1 = new Miner; auto miner2 = new Miner(*miner1); // 代碼執行到這裏 // @表示地址 usecount是引用計數 // miner1的gold @0x605f40 // miner2的gold @0x605f40 // shared_ptr的usecount是2 // 可見miner1和miner2的gold指向同一個對象 // 引用計數正確 auto gold = miner2->base(); // 代碼執行到這裏 // gold @0x605f40 miner1->dig(); cout << gold->total << endl; miner2->dig(); cout << gold->total << endl; miner1->dig(); cout << gold->total << endl; delete miner1; // 代碼執行到這裏 // miner1的gold (null) // miner2的gold @0x605f40 // shared_ptr的usecount是1 // 引用計數正確 miner2->dig(); cout << gold->total << endl; delete miner2; // 代碼執行到這裏 // miner1的gold (null) // miner2的gold @0x605f20 // miner2管理的對象(@0x605f40) 已被銷燬 // 調用了Gold的析構函數 // gold->totle值爲-1 // 至於miner2的gold @0x605f20 ?? // 管它呢,反正已引用不到 cout << gold->total << endl; int *p2; { auto p1 = make_shared<int>(5); p2 = p1.get(); // 代碼執行到這裏 // p1 @0x605f60 // usecount是1 // p2 指向@0x605f60 } // 代碼執行到這裏 // 代碼塊出棧了,p1被銷燬 // usecount變爲0,因此p1管理的對象也被銷燬了 // ***這是爲何不建議用get的緣由 // 雖然能夠正確輸出p2所指向的對象,可是這是不肯定的 // p2就是所謂的野指針了 cout << *p2 << endl; shared_ptr<int> p4; { auto p3 = make_shared<int>(5); p4 = p3; // 代碼執行到這裏 // p3 @0x605f60 // p4 @0x605f60 // usecount是2 } // 代碼執行到這裏 // 代碼塊出棧了,p3被銷燬 // usecount變爲1,p3並未銷燬所管理的對象 // p4所管理的對象能夠正確輸出 cout << *p4 << endl; return 0; }