1. 程式人生 > >C++11--智慧指標shared_ptr,weak_ptr,unique_ptr

C++11--智慧指標shared_ptr,weak_ptr,unique_ptr

共享指標 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();
}