天天看点

c++11之shared_ptr智能指针使用

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分配的内存,记住传递给它一个删除器。