溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中的智能指針shared_ptr和unique_ptr怎么使用

發(fā)布時間:2022-08-23 10:21:23 來源:億速云 閱讀:108 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹“C++中的智能指針shared_ptr和unique_ptr怎么使用”,在日常操作中,相信很多人在C++中的智能指針shared_ptr和unique_ptr怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C++中的智能指針shared_ptr和unique_ptr怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    shared_ptr

    基本用法: 可以通過構造函數, make_shared<T>輔助函數和reset()方法來初始化shared_ptr

    1. 初始化方法

        shared_ptr<int> p1(new int(1));
        shared_ptr<int> p2 = p1;
        shared_ptr<int> p3;
        p3.reset(new int(1));
        shared_ptr<int> p4 = make_shared<int>(int(5));

    優(yōu)先使用make_shared來構造, 更加高效

    不能用一個原始指針直接賦值智能指針, 以下方式是錯誤的

    shared_ptr<int> p5=new int(1); //error

    2.獲取智能指針的原始指針: 通過get方法

        shared_ptr<int> ptr = make_shared<int>(int(5));
        int *p=ptr.get();

    3.指定刪除器:自定義指針銷毀方式

    void ptr_deleter(const int*p)
    {
        delete p;
    }
    shared_ptr<int> p(new int, ptr_deleter);

    第二個參數指定刪除器(一個可調用對象, 其中參數為該類型的指針, 如上面為int*)

    當shared_ptr引用計數為0時, 調用傳入的而不是默認的刪除器來釋放對象的內存

    當用shared_ptr管理動態(tài)數組時, 需要指定刪除器, 因為shared_ptr默認刪除器不支持數組對象

    如下使用lambda表達式作為刪除器

    shared_ptr<int> p(new int[10],[](int*p){delete []p;});

    通過default_delete作為刪除器, 同時封裝一個make_shared_array函數來支持數組

    template<typename T>
    shared_ptr<T> make_shared_array(int size)
    {
        return shared_ptr<T>(new T[size],default_delete<T[]>());
    }

    (自測)貌似這樣也支持數組

    shared_ptr<int[]> ptr(new int[10]);

    使用shared_ptr注意

    (1)不要用一個原始指針初始化多個shared_ptr

        int *ptr = new int;
        shared_ptr<int> p1(ptr);
        shared_ptr<int> p2(ptr);  //錯誤

    (2)不要在函數實參中創(chuàng)建shared_ptr

    function(shared_ptr<int>(new int),g());

    參數的計算順序可能沒有固定順序, 若是new int后執(zhí)行g()拋出異常, 則shared_ptr還沒有創(chuàng)建, 則new int內存泄漏了

    (3)不要用this指針構造shared_ptr作為返回值

    class A
    {
    public:
        shared_ptr<A> get_self()
        {
            return shared_ptr<A>(this);
        }
        ~A()
        {
            cout << ("destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> p1(new A);
        shared_ptr<A> p2 = p1->get_self();
        return 0;
    }

    destructor

    destructor

    以上代碼p1和p2相當于同一個new A初始化, 會shared_ptr銷毀時, 會重復析構

    正確做法:

    讓該類繼承enable_shared_from_this<>, 同時調用shared_from_this()返回

    class A :public enable_shared_from_this<A>    //繼承
    {
    public:
        shared_ptr<A> get_self()
        {
            return shared_from_this();            //調用該函數
        }
        ~A()
        {
            cout << ("destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> p1(new A);
        shared_ptr<A> p2 = p1->get_self();
        return 0;
    }

    destructor

    只要用shared_ptr, 調用的成員函數里都不能使用this構造, 否則都會出錯

    class A
    {
    public:
        void test()
        {
            shared_ptr<A>(this); //錯誤
        }
        ~A()
        {
            cout<<(  "destructor"  )<<endl;
        }
    };
    shared_ptr<A> p(new A);
    p->test()

    另外, 不要在構造函數里使用shared_from_this

    (4)避免循環(huán)引用

    以下代碼會由于循環(huán)引用, 引用計數值都為1, 導致兩個指針都不會析構

    class A;
    class B;
    class A
    {
    public:
        shared_ptr<B> b_ptr;
        ~A()
        {
            cout << ("A destructor") << endl;
        }
    };
    class B
    {
    public:
        shared_ptr<A> a_ptr;
        ~B()
        {
            cout << ("B destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> a_p(new A);
        shared_ptr<B> b_p(new B);
        a_p->b_ptr=b_p;
        b_p->a_ptr=a_p;
    }

    //沒有輸出

    unique_ptr

    unique_ptr不允許復制, 不允許其他的智能指針共享其內部的指針, 但可以轉移

        unique_ptr<int> ptr(new int);
       // unique_ptr<int> ptr2=ptr;    error 不可以賦值
        unique_ptr<int> ptr3=move(ptr); //用move進行轉移
        assert(ptr!=nullptr); //轉移后ptr為nullptr

    自定義make_unique函數且讓其支持定長數組

    思路

    不是數組, 返回unique_ptr<T>

    是數組且非定長數組, 返回unique_ptr<T>, 即不應該調用make_unique<T[10]>(10)而是make_unique<T[]>(10)

    最后過濾掉該定長數組(函數聲明為delete)

    // !is_array_v確定不是數組, 返回unique_ptr<T>
    template<typename T,typename ...Args>
    enable_if_t<!is_array_v<T>,unique_ptr<T>> make_unique_(Args&&...args)
    {
        return unique_ptr<T>( new T(forward<Args>(args)...));
    }
    //定長數組如T[10],  不應該調用make_unique<T[10]>(10);而是make_unique<T[]>(10);
    // is_array_v確定是數組且!extent_v<T>確定非定長數組, 返回unique_ptr<T>
    template<typename T,typename ...Args>
    enable_if_t<is_array_v<T>&&!extent_v<T>,unique_ptr<T>> make_unique_(size_t size)
    {
        using U=remove_extent_t<T>;
        return unique_ptr<T>( new U[size]);
    }
    //否之過濾掉該定長數組
    template<typename T,typename ...Args>
    enable_if_t<extent_v<T>,void> make_unique_(Args&&...)=delete;
        unique_ptr<int> ptr= make_unique_<int>(10);
        unique_ptr<int[]> ptr1= make_unique_<int[]>(10);

    不過unique_ptr本身也支持數組, shared_ptr自測也支持, 如下

        unique_ptr<A[]> ptr1(new A[10]);
        shared_ptr<A[]> ptr2(new A[10]);

    unique_ptr也支持刪除器, 但和shared_ptr有區(qū)別, 要指定刪除器類型

        shared_ptr<A> p1(new A[10],[](A*p){delete []p;});
       // unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 錯誤
        unique_ptr<A,void(*)(A*)> p2(new A[10],[](A*p){delete []p;}); //正確

    如果希望lambda刪除器捕獲變量, 則需要用function包裝

        unique_ptr<A,void(*)(A*)> p1(new A[10],[&](A*p){delete []p;});       //錯誤
        unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正確

    到此,關于“C++中的智能指針shared_ptr和unique_ptr怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI