环境: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:如何保证可以调用多种形式的构造函数?