shared_ptr类模板介绍
share_ptr是智能指针模板,创建智能指针对象时,需要指定可以指向的类型:
shared_ptr< string > p1;//指向string类型
shared_ptr< list<string> > p2;//指向string类型的list
默认的智能指针对象中保存着空指针,智能指针的操作和普通指针一样,支持解引用(*)和成员操作符(->),也可以用智能指针对象来判空操作。
shared_ptr< string > sp1;//指向string类型
if(!sp1)
{
cout << "it is empty\n";
sp1 = make_shared<string>("hello world");
}
cout << *sp1 <<endl;
//it is empty
//hello world
相对于unique_ptr独有操作:
make_shared<T>(args)
//返回一个shared_ptr,指向动态分配的类型为T的对象,使用args初始化此对象
shared_ptr<T>p(q)
//p是shared_ptr q的拷贝
p = q;
//p和q都是shared_ptr,所保存的指针必须能相互转换,p原来所指的计数器减一,q原来所指的计算器加一。
p.use_count()
//返回与p共享对象的智能指针数量,可能很慢,主要用于调试。
shared_ptr对象初始方式
最安全的分配和使用动态内存的方式是调用make_shared的标准库,例如:
//指向一个int类型值为42的share_ptr;
shared_ptr<int> sp1 = make_shared<int>();
//指向一个string类型的shared_ptr
shared_ptr<string> sp2 = make_shared<string>("hello world");
也可以中new方式进行初始化:
//指向一个int类型值为42的share_ptr;
shared_ptr<int> sp1(new int());
//指向一个string类型的shared_ptr
shared_ptr<string> sp2(new string("hello world"));
在c++11中,我们可以用auto定义对象来保存make_shared的返回结果,这种方式比较简单,例如:
//指向一个int类型值为42的share_ptr;
auto sp1 = make_shared<int>();
//指向一个string类型的shared_ptr
auto sp2 = make_shared<string>("hello world");
自动销毁所管理的对象
share_ptr智能指针是允许多个share_ptr同时指向某个对象,具有共享的特性;它们通过引用计数器方式,实现对对象的管理;
当一个shared_ptr对象被销毁时,其析构函数会递减它所指向的对象的引用计数器。当引用计数器变为 零时,shared_ptr的析构函数就会销毁对象,并释放它占用的内存。
int main()
{
auto p1 = make_shared<int>();
//wp1是p1所指向对象的观察器
weak_ptr<int> wp1 = p1;
cout <<"before " <<"wp1 point to obj ref num: " << wp1.use_count() << " " <<endl;
auto p2 = make_shared<int>();
//wp2是p2所指向对象的观察器
weak_ptr<int> wp2 = p2;
cout <<"before " <<"wp2 point to obj ref num: " << wp2.use_count() << " " <<endl;
//复制操作
p1 = p2;//给p1赋值,令他指向另外一个地址
//递增p2原来指向对象的计数器
//递减p1原来指向对象的计数器
//p1原来指向对象的计数器变为零,对象内存自动释放
cout <<"after " << "wp2 point to obj ref num: " << wp2.use_count() << " " <<endl;
cout <<"after " << "wp1 point to obj ref num: " << wp1.use_count() << " " <<endl;
return ;
}
运行结果:
before wp1 point to obj ref num:
before wp2 point to obj ref num:
after wp2 point to obj ref num:
after wp1 point to obj ref num:
NOTE:
一旦引用计数器不为零,其所指向的内存空间都不会被释放,造成内存泄漏;因此shared_ptr无用武之地后,保证智能指针对象及时析构,变得非常重要,否则浪费内存。
定制删除器
默认情况下,shared_ptr假定它们指向的是动态内存。因此,一个share_ptr被销毁时,它默认对他管理的指针进行delete操作。为了能够用shared_ptr来管理非动态内存的指针时,我们需要特殊定制一个函数来替代delete操作。这个函数就叫做删除器(deleter)。
下面展示删除器的使用,其入参是T*类型,代码如下:
shared_ptr<int> sp(new int(), [](int *p){
cout << "call own deleter function\t ";
cout << "value: " << *p << endl;
delete p;
//指向的对象析构,调用删除器,lambda表达
sp.reset();
运行结果:
智能指针陷阱
智能指针可以提供对动态分配的内存进行安全而又方便的管理,当这是建立在正确使用的前提下。为了正确使用智能指针,我们必须坚持一个基本规范:
- 不用使用相同的内置指针初始化或者reset多个智能指针
- 不delete get()返回的指针
- 不使用get()初始化或者reset另外一个指针
- 如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了
- 如果你使用的指针指针管理的指针不是new分配的内存,记住传递给它一个删除器。