c++11之shared_ptr的使用記錄


環境:vs 2013、win7
作用:
利用引用計數的方式,進而避免堆內存出現意外釋放,或者內存泄漏這些危險。
使用方式:
1 std::shared_ptr<Type> 對Type類型,記錄其使用數、並可以通過訪問指針的方式,直接訪問Type  中內容,再在使用數為0時,將對應的Type類型內存釋放。
//std::shared_ptr<TestShared> testSharedMake = std::make_shared<TestShared>();
std::shared_ptr<TestShared> testSharedMake0 = testSharedMake;
如上述,當出現對應的賦值語句時,都將導致使用計數增加,(如果原來有引用數,則原來的引用數將減少),當該std::shared_ptr變量被釋放(比如離開作用域被回收,或者賦值為nullptr),引用會被減少。
 
2 如何對Type類型指針,構建std::shared_ptr
(1)std::make_shared<TestShared>() ,推薦使用。如果需要調用其它構造函數形式,可以類似調用std::make_shared<TestShared>(x, y..)
(2)std::shared_ptr<TestShared>(new TestShared()); 不推薦使用
很多帖子都書寫並貼上數據闡述了:make_shared可以把new控制為一次,所以效率更高。另外就是書寫更加一致,畢竟沒有delete了,如果還是手動書寫new,會很容易讓碼農們覺得錯漏了什么。
//make_shared:構造代碼
    // TEMPLATE FUNCTION make_shared
template<class _Ty,
    class... _Types> inline
        shared_ptr<_Ty> make_shared(_Types&&... _Args)
    {    // make a shared_ptr
    _Ref_count_obj<_Ty> *_Rx =
        new _Ref_count_obj<_Ty>(_STD forward<_Types>(_Args)...);

    shared_ptr<_Ty> _Ret;
    _Ret._Resetp0(_Rx->_Getptr(), _Rx);
    return (_Ret);
    }
    template<class... _Types>
        _Ref_count_obj(_Types&&... _Args)
        : _Ref_count_base()
        {    // construct from argument list
        ::new ((void *)&_Storage) _Ty(_STD forward<_Types>(_Args)...);
        }
//std::shared_ptr<TestShared>(new TestShared()) 代碼:
    template<class _Ux>
        explicit shared_ptr(_Ux *_Px)
        {    // construct shared_ptr object that owns _Px
        _Resetp(_Px);
        }

    template<class _Ux>
        void _Resetp(_Ux *_Px)
        {    // release, take ownership of _Px
        _TRY_BEGIN    // allocate control block and reset
        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));
        _CATCH_ALL    // allocation failed, delete resource
        delete _Px;
        _RERAISE;
        _CATCH_END
        }
 
3 注意事項,除了上面一項將的構建shared_ptr變量,其它時候,千萬不要想當然的用Type*轉換為shared_ptr。因為如此是會重新構建一項新的獨立的使用計數,如此將導致引用計數最終遞減為0時,將會觸發多於一次對同一塊內存的釋放。如下述,是不允許的。(在后面的sample給出代碼中,可以把相關注釋掉的代碼打開,即可以看到出現問題。)
std::shared_ptr<TestShared> testShared = std::shared_ptr<TestShared>(value); //error
 
4 如果需要從this指針中轉換得到std::shared_ptr,此時需要將管理的類型繼承於:enable_shared_from_this,並使用由其繼承得來的shared_from_this(),記得得到期望的shared_ptr數值。如下:
class TestShared : public std::enable_shared_from_this<TestShared>
enable_shared_from_this:集成該類,主要是可以在構建時,記錄一個weak_ptr,並在需要時,傳送出去,並生成shared_ptr
template<class _Ty1,
    class _Ty2>
    inline void _Do_enable(
        _Ty1 *_Ptr,
        enable_shared_from_this<_Ty2> *_Es,
        _Ref_count_base *_Refptr)
    {    // reset internal weak pointer
    _Es->_Wptr._Resetw(_Ptr, _Refptr);
    }

 

//sample 代碼:
#ifndef _TEST_SHARED_H_
#define _TEST_SHARED_H_

#include <memory>
class  TestShared : public std::enable_shared_from_this<TestShared>
{
public:
     TestShared();
    ~ TestShared();

    std::shared_ptr<TestShared> GetSharedObject();
private:
};

 TestShared:: TestShared()
{
}

 TestShared::~ TestShared()
{
}

 std::shared_ptr<TestShared>  TestShared::GetSharedObject()
 {
     return shared_from_this();
 }

#endif //_TEST_SHARED_H_

    std::shared_ptr<TestShared> testSharedMake = std::make_shared<TestShared>();
    std::cout << "testSharedMake \t\t"<<" shared_count: " << testSharedMake.use_count() << std::endl;
    std::shared_ptr<TestShared> testSharedMake0 = testSharedMake;
    std::cout << "testSharedMake \t\t"<< " shared_count: " << testSharedMake.use_count() << std::endl;
    std::cout << "testSharedMake0 \t\t"<< " shared_count: " << testSharedMake0.use_count() << std::endl;

    TestShared* value = testSharedMake.get();

    //std::shared_ptr<TestShared> testShared = std::shared_ptr<TestShared>(value);
    //std::cout << "testShared \t\t" << " shared_count: " << testShared.use_count() << std::endl;
    //std::cout << "testSharedMake \t\t" << " shared_count: " << testSharedMake.use_count() << std::endl;

    std::shared_ptr<TestShared> testSharedFromThis = value->GetSharedObject();
    //std::cout << "testShared \t\t" << " shared_count: " << testShared.use_count() << std::endl;
    std::cout << "testSharedMake \t\t" << " shared_count: " << testSharedMake.use_count() << std::endl;
    std::cout << "testSharedFromThis \t\t" << " shared_count: " << testSharedFromThis.use_count() << std::endl;

    std::shared_ptr<TestShared> testSharedFromThis0 = testSharedMake->GetSharedObject();
    //std::cout << "testShared \t\t\t" << " shared_count: " << testShared.use_count() << std::endl;
    std::cout << "testSharedMake \t\t" << " shared_count: " << testSharedMake.use_count() << std::endl;
    std::cout << "testSharedMake0 \t\t" << " shared_count: " << testSharedMake0.use_count() << std::endl;
    std::cout << "testSharedFromThis0 \t\t" << " shared_count: " << testSharedFromThis0.use_count() << std::endl;

附上上述運行結果:

testSharedMake shared_count: 1
testSharedMake shared_count: 2
testSharedMake0 shared_count: 2
testSharedMake shared_count: 3
testSharedFromThis shared_count: 3
testSharedMake shared_count: 4
testSharedMake0 shared_count: 4
testSharedFromThis0 shared_count: 4

遺留問題:
1 make_shared:如何保障只調用一次new
2 make_shared:如何保證可以調用多種形式的構造函數?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM