環境: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:如何保證可以調用多種形式的構造函數?