share_ptr 的 知识梳理笔记
最近学习share_ptr 的时候发现这是个很有用的智能指针,无论是内存管理还是线程安全,以及自定义删除器, 所以觉得还是记录分享一下,同时也巩固一下自己的学习成果
1,share_ptr 是何物
采用引用计数的智能指针。 shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作。头文件:。
基本操作:shared_ptr的创建、拷贝、绑定对象的变更(reset)、shared_ptr的销毁(手动赋值为nullptr或离开作用域)、指定deleter等操作。
shared_ptr的创建,有两种方式,一,使用函数make_shared(会根据传递的参数调用动态对象的构造函数);二,使用构造函数(可从原生指针、unique_ptr、另一个shared_ptr创建)
shared_ptr<int> p1 = make_shared<int>(1);// 通过make_shared函数
shared_ptr<int> p2(new int(2));// 通过原生指针构造
此外智能指针若为“空“,即不指向任何对象,则为false,否则为true,可作为条件判断。可以通过两种方式指定deleter,一是构造shared_ptr时,二是使用reset方法时。可以重载的operator->, operator *,以及其他辅助操作如unique()、use_count(), get()等成员方法。
2,shared_ptr的线程安全性
boost官方文档对shared_ptr线程安全性的正式表述是:shared_ptr对象提供与内置类型相同级别的线程安全性。【shared_ptrobjects offer the same level of thread safety as built-in types.】具体是以下三点。
同一个shared_ptr对象可以被多线程同时读取。【A shared_ptrinstance can be “read” (accessed using only const operations)simultaneously by multiple threads.】
不同的shared_ptr对象可以被多线程同时修改(即使这些shared_ptr对象管理着同一个对象的指针)。【Different shared_ptr instances can be “written to”(accessed using mutable operations such as operator= or reset) simultaneouslyby multiple threads (even when these instances are copies, and share the samereference count underneath.) 】
任何其他并发访问的结果都是无定义的。【Any other simultaneous accesses result in undefined behavior.】同一个shared_ptr对象不能被多线程直接修改,但可以通过原子函数完成。
我简单地理解为,除了多线程直接修改(非原子函数)同一个share_ptr ,其他都是安全的
3,share_ptr 使用中可能碰到的有意思问题,循环引用
“循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用。导致引用计数失效。而解决的办法其实是另一个weak_ptr 智能指针的使用,这里具体就不多说了,需要知道的是,weak_ptr不参与引用计数, 两个常用的功能函数:expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用指针, 譬如
void doSomthing()
{
shared_ptr<B> pp = pb.lock();
if(pp)//通过lock()方法来判断它所管理的资源是否被释放
{
cout<<"sb use count:"<<pp.use_count()<<endl;
}
}
4,share_ptr 的自定义删除器
这个直接上代码吧,两个代码片段,看了应该就明白了,不明白的你再多看两遍,呵呵~~
#include <iostream>
#include <memory>
struct dialog_t { };
template<class T>
struct deleter_t
{
void operator () (T* x) const
{
if(x != NULL )
{
std::cout << __LINE__ << std::endl;
delete x;
x=NULL;
}
}
};
int main ()
{
auto const p = std::shared_ptr<dialog_t>(new dialog_t, deleter_t<dialog_t>{});
}
分割开,上面这个就是个单独的代码片,下面的是有测试用例的
template<class T>//注意这里有模版
struct Del
{
void operator()(const T* ptr)
{
delete ptr;
}
};
struct Free//注意这里没有模版
{
void operator()(void* ptr)
{
free(ptr);
}
};
struct Fclose
{
void operator()(FILE* ptr)
{
fclose(ptr);
}
};
template<class T,class Deleter=Del<T>>
class SharedPtr
{
public:
SharedPtr(T* ptr, Deleter del)
:_ptr(ptr)
, _pCount(new long(1))
, _del(del)
{}
SharedPtr(T* ptr)
:_ptr(ptr)
, _pCount(new long(1))
{}
~SharedPtr()
{
_Release();
}
protected:
void _Release()
{
if (--*_pCount == 0)
{
_del(_ptr);
delete _pCount;
}
}
private:
T* _ptr;
long* _pCount;
Deleter _del;
};
测试用例
void Test()
{
SharedPtr<int>sp1(new int(1));
SharedPtr<int,Free>sp2((int*)malloc(sizeof(int) * 10), Free());//注意怎么调用的
}
先到这里,后面还有的话再补上,当然可爱的你也可以在评论里直接追加,3q~