1. 程式人生 > >C++智慧指標auto_ptr使用講解

C++智慧指標auto_ptr使用講解

auto_ptr是C++98標準庫提供的一個智慧指標,但已被C++11明確宣告不再支援。

auto_ptr具有以下缺陷:

  • auto_ptr有拷貝語義,拷貝後源物件變得無效,這可能引發很嚴重的問題;而unique_ptr則無拷貝語義,但提供了移動語義,這樣的錯誤不再可能發生,因為很明顯必須使用std::move()進行轉移。
#include <iostream>
#include <tr1/memory>
using namespace std::tr1;
using namespace std;

class A
{
public:
    string id;
    A
(string id):id(id) { cout<<id<<":建構函式"<<endl; } ~A() { cout<<id<<":解構函式"<<endl; } }; int main() { auto_ptr<A> auto_ap(new A("auto_ptr")),auto_bp; cout<<auto_ap.get()<<endl; auto_bp = auto_ap; cout<<
auto_ap.get()<<endl; unique_ptr<A> unique_ap(new A("unique_ptr")),unique_bp; cout<<unique_ap.get()<<endl; // unique_bp = unique_ap; // 報錯 unique_bp = move(unique_ap); cout<<unique_ap.get()<<endl; return 0; }

執行結果:

auto_ptr:建構函式
0x6115d0
0
unique_ptr:建構函式
0x6115f0
0
unique_ptr:解構函式
auto_ptr:解構函式
  • auto_ptr不可作為容器元素,unique_ptr可以作為容器元素。因為auto_ptr的拷貝和賦值具有破壞性,不滿足容器要求:拷貝或賦值後,兩個物件必須具有相同值。
  • auto_ptr不可指向動態陣列,unique_ptr可以指向動態陣列。因為unique_ptr有unique_ptr<T[]>過載版本,銷燬動態物件時呼叫delete[]。
#include <iostream>
#include <memory>
using namespace std;

class A
{
public:
    string id;
    A(string id):id(id)
    {
    	cout<<id<<":建構函式"<<endl;
    }
    ~A()
    {
    	cout<<id<<":解構函式"<<endl;
    }
};

int main() 
{
    //auto_ptr<A[]> auto_ap(new A[1]{A("unique_ptr")});  // 報錯
    unique_ptr<A[]> unique_ap(new A[1]{A("unique_ptr")});
    return 0;
}


  • auto_ptr不可以自定義刪除器deleter,而unique_ptr可以。
#include <iostream>
#include <string>
#include <tr1/memory>

using namespace std;
using namespace std::tr1;

class A
{
public:
    string id;
    A(string id):id(id)
    {
    	cout<<id<<":建構函式"<<endl;
    }
    ~A()
    {
    	cout<<id<<":解構函式"<<endl;
    }

};

int main() 
{
    unique_ptr<A,void(*)(A*)> unique_ap(
    new A[2]
    {
		A("unique_ptr0"),A("unique_ptr1")
	},
    [](A *a)
    {
    	delete []a;
    });
    return 0;
}

執行結果:

unique_ptr0:建構函式
unique_ptr1:建構函式
unique_ptr1:解構函式
unique_ptr0:解構函式
#include <iostream>
#include <string>
#include <tr1/memory>
using namespace std;
using namespace std::tr1;

class Test
{
public:
    Test(string s)
    {
        str = s;
       cout<<"Test creat\n";
    }
    ~Test()
    {
        cout<<"Test delete:"<<str<<endl;
    }
    string& getStr()
    {
        return str;
    }
    void setStr(string s)
    {
        str = s;
    }
    void print()
    {
        cout<<str<<endl;
    }
private:
    string str;
};
 
 
int main()
{
    auto_ptr<Test> ptest(new Test("123"));
    ptest->setStr("hello ");
    ptest->print();
    ptest.get()->print();   //成員函式get()返回一個原始的指標
    ptest->getStr() += "world !";
    (*ptest).print();

    //Test creat
    //Test delete:hello world !
    ptest.reset(new Test("123"));  //成員函式reset()重新繫結指向的物件,而原來的物件則會被釋放
    ptest->print();

    //ptest2會接管ptest原來的記憶體管理權,ptest會變為空指標,如果ptest2原來不為空,則它會釋放原來的資源
    auto_ptr<Test> ptest2(new Test("456"));
    ptest2 = ptest;
    ptest2.release();
    //ptest2->print(); //段錯誤 (核心已轉儲)
    //判斷一個智慧指標是否為空不能使用if(ptest == NULL),應該使用if(ptest.get() == NULL)
    if(ptest.get() == NULL)
    {
        cout<<"ptest = NULL\n";
    }
    //成員函式是release,這個函式只是把智慧指標賦值為空,但是它原來指向的記憶體並沒有被釋放,相當於它只是釋放了對資源的所有權
    //ptest.release();
    return 0;
}