C++11--智慧指標shared_ptr,weak_ptr,unique_ptr
阿新 • • 發佈:2018-12-30
共享指標 shared_ptr
/*********** Shared_ptr ***********/ // 為什麼要使用智慧指標,直接使用裸指標經常會出現以下情況 // 1. 當指標的生命長於所指的資源:野指標 // 2. 當指標的生命短於所指的資源:資源洩漏 // // 智慧指標: 確保指標和資源的生命週期相同 class Dog { string m_name; public: void bark() { cout << "Dog " << m_name << " rules!" << endl; } Dog(string name) { cout << "Dog is created: " << name << endl; m_name = name; } Dog() { cout << "Nameless dog created." << endl; m_name = "nameless"; } ~Dog() { cout << "dog is destroyed: " << m_name << endl; } //void enter(DogHouse* h) { h->setDog(shared_from_this()); } // Dont's call shared_from_this() in constructor }; class DogHouse { shared_ptr<Dog> m_pD; public: void setDog(shared_ptr<Dog> p) { m_pD = p; cout << "Dog entered house." << endl;} }; int main () { shared_ptr<Dog> pD(new Dog("Gunner")); shared_ptr<Dog> pD = make_shared<Dog>(new Dog("Gunner")); // 另一種方式,更快且更安全 pD->bark(); // 過載了箭頭,可以像直接操作指標一樣進行操作 cout << pD.use_count(); // 指示有多少shared_ptr指向物件 (*pD).bark(); //DogHouse h; // DogHouse* ph = new DogHouse(); // ph->setDog(pD); // delete ph; //auto pD2 = make_shared<Dog>( Dog("Smokey") ); // 不要對棧上的物件使用shared_ptr // auto pD2 = make_shared<Dog>( *(new Dog("Smokey")) ); // pD2->bark(); // // 物件一建立就應該立馬放入智慧指標中,避免使用裸指標 // Dog* p = new Dog(); // 不是一個好的使用方式,容易出錯 // shared_ptr<int> p1(p); // shared_ptr<int> p2(p); // 出錯,p會被delete兩次 shared_ptr<Dog> pD3; pD3.reset(new Dog("Tank")); pD3.reset(); // Dog銷燬。同: pD3 = nullptr; // //pD3.reset(pD.get()); // crashes返回raw point /********** 自定義Deleter ************/ shared_ptr<Dog> pD4( new Dog("Victor"), [](Dog* p) {cout << "deleting a dog.\n"; delete p;} ); // 預設的deleter是operator delete. //shared_ptr<Dog> pDD(new Dog[3]); // Dog[1]和Dog[2]記憶體洩漏 shared_ptr<Dog> pDD(new Dog[3], [](Dog* p) {delete[] p;} ); // 所有3個Dog都會被delete
弱指標 weak_ptr
/*********** weak_ptr *********************/ // weak_ptr對所指物件沒有所有權 // 物件何時delete,怎麼delete跟我沒有關係 // 所以weak_ptr不是一直有效的,需要檢查有效性。 class Dog { //shared_ptr<Dog> m_pFriend; weak_ptr<Dog> m_pFriend; //跟Dog* m_pFriend類似,不過提供了一層保護,沒有人可以delete它。並不是永遠有效的,如果weak_ptr指向的指標被delete了 public: string m_name; void bark() { cout << "Dog " << m_name << " rules!" << endl; } Dog(string name) { cout << "Dog is created: " << name << endl; m_name = name; } ~Dog() { cout << "dog is destroyed: " << m_name << endl; } void makeFriend(shared_ptr<Dog> f) { m_pFriend = f; } void showFriend() { //cout << "My friend is: " << m_pFriend.lock()->m_name << endl; if (!m_pFriend.expired()) cout << "My friend is: " << m_pFriend.lock()->m_name << endl; cout << " He is owned by " << m_pFriend.use_count() << " pointers." << endl; }//lock()將其轉化為shared_ptr,檢查指標有效性,同時保證指標不被delete }; int main () //使用共享指標的話,會資源洩漏。因為迴圈引用。 { shared_ptr<Dog> pD(new Dog("Gunner")); shared_ptr<Dog> pD2(new Dog("Smokey")); pD->makeFriend(pD2); pD2->makeFriend(pD); pD->showFriend(); }
unique_ptr
/*********** unique_ptr *********************/ // Unique指標:獨佔物件所有權,開銷比shared_ptr小 class Dog { //Bone* pB; unique_ptr<Bone> pB; // 防止記憶體洩漏,即使建構函式在new之後丟擲異常 public: string m_name; void bark() { cout << "Dog " << m_name << " rules!" << endl; } Dog() { pB = new Bone(); cout << "Nameless dog created." << endl; m_name = "nameless"; } Dog(string name) { cout << "Dog is created: " << name << endl; m_name = name; } ~Dog() { delete pB; cout << "dog is destroyed: " << m_name << endl; } }; void test() { //Dog* pD = new Dog("Gunner"); unique_ptr<Dog> pD(new Dog("Gunner")); pD->bark(); /* pD做許多操作*/ //Dog* p = pD.release(); //返回raw point,同時轉讓原物件的所有權,不會再自動delete Dog pD = nullptr; // Dog("Gunner")被銷燬 //pD.reset(new Dog("Smokey")); // Dog("Gunner")被銷燬 if (!pD) { cout << "pD is empty.\n"; } //delete pD; } void f(unique_ptr<Dog> p) { p->bark(); } unique_ptr<Dog> getDog() { unique_ptr<Dog> p(new Dog("Smokey")); return p; // 傳值返回,會自動使用move語義 } void test2() { unique_ptr<Dog> pD(new Dog("Gunner")); unique_ptr<Dog> pD2(new Dog("Smokey")); pD2 = move(pD); // 1. Smokey is destroyed // 2. pD becomes empty. // 3. pD2 owns Gunner. pD2->bark(); // f(move(pD)); // "Gunner"所有權已不屬於pD,在f結束後銷燬 // if (!pD) { // cout << "pD is empty.\n"; // } // // unique_ptr<Dog> pD2 = getDog(); // pD2->bark(); unique_ptr<Dog[]> dogs(new Dog[3]); //引數支援陣列,不需要像shared_ptr定義deleter。因為unique_ptr對陣列進行了偏特化 dogs[1].bark(); //(*dogs).bark(); // * is not defined } void test3() { // prevent resource leak even when constructor fails } int main () { test2(); }