C++智能指针

来源:互联网 发布:阿里云 paas iaas 编辑:程序博客网 时间:2024/06/06 04:34

std::shared_ptr

初始化

构造函数初始化:

std::shared_ptr<int> p(new int(1));

std::make_shared< T >初始化

std::shared_ptr<int> p = std::make_shared<int>(1);

注意:不能将一个原始指针直接复制给一个智能指针。

std::shared_ptr<int> p = new int(1);//编译报错

获取原始指针

可以用get方法来返回原始指针。

std::shared_ptr<int> p(new int(1));int* ptr = p.get();

指定删除器

智能指针初始化可以指定删除器。

void DeleteIntPtr(int* p){    delete p;}std::shared_ptr<int> p(new int, DeleteIntPtr);

使用lambda表达式:

std::shared_ptr<int> p(new int, [](int* p){delete p};);

当使用shared_ptr管理动态数组是,需要指定删除器,因为其默认删除器不支持数组对象。

std::shared_ptr<int> p(new int[10], [](int* p){delete[] p};);

可以将std::default_delete作为删除器,其内部是通过调用delete实现的。

std::shared_ptr<int> p(new int[10], std::default_delete<int[]>);

使用shared_ptr需要注意的问题

  • 不要用原始指针初始化多个shared_ptr
int* ptr=new int;std::shared_ptr<int> p1(ptr);std::shared_ptr<int> p2(ptr);//错误
  • 不要在实参中创建shared_ptr
function(shared_ptr<int>(new int),g());//有缺陷

由于不同的编译器函数参数的计算顺序可能不同,可能先new int,然后调用g(),如果g()发生异常,shared_ptr< int >还没有创建,则int内存泄漏。正确写法应该先创建智能指针。

shared_ptr<int> p(new int());function(p, g());
  • 通过shared_from_this()返回this指针,不要将this指针作为shared_ptr返回出来,否则会导致重复析构。
struct A{    shared_ptr<A> Getself(){        return shared_ptr<S>(this);    }};int main(){    shared_ptr<A> sp1(new A);    shared_ptr<A> sp2=sp1->Getself();    return 0;}

由于用同一个指针(this)构造了两个智能指针,所以会造成重复析构。
正确返回this 的shared_ptr的做法是:让目标类通过派生std::enable_shared_from_this< T >类,然后使用基类的成员函数shared_from_this()来返回。

class A:public std::enable_shared_from_this<A>{    std::shared_ptr<A> GetSelf(){        return shared_from_this();    }};std::shared_ptr<A> spy(new A);std::shared_ptr<A> p=spy->GetSelf();
  • 避免循环引用
    循环引用会导致内存泄漏,下面是一个典型的循环引用的场景:
struct A{    std::shared_ptr<B> bptr;    ~A()  { cout << "A is deleted!" << endl; }};struct B{    std::shared_ptr<A> aptr;    ~B()  { cout << "B is deleted!" << endl; }};void TestPtr(){    std::shared_ptr<A> ap(new A);    std::shared_ptr<B> bp(new B);    ap->bptr = bp;    bp->aptr = ap;}

循环引用导致ap和bp的引用计数都为2,离开作用域后减为1,产生内存泄漏。

std::unique_ptr

unique_ptr不允许其他智能指针共享其内部的指针。

unique_ptr<T> myPtr(new T);unique_ptr<T> myOtherPtr=myPtr;//错误unique_ptr<T> myOtherPtr=std::move(myPtr);//可以移动

unique_ptr可以指向一个数组:

std::unique_ptr<int []>ptr(new int10[]);

unique_ptr指定删除器和shared_ptr有差别:

std::unique_ptr<int,void(*)(int*)>ptr(new int(1),[](int*p){delete p;});

std::weak_ptr

weak_ptr用来监视shared_ptr,不会使引用计数加1,不共享指针,不能操作资源。

基本用法

  • 通过use_count()来获得当前观测资源的引用计数
shared_ptr<int> sp(new int(10));weak_ptr<int> wp(sp);cout<<wp.use_count()<<endl;//结果为1
  • 通过expired()来判断观测的资源是否被释放
shared_ptr<int> sp(new int(10));weak_ptr<int> wp(sp);if(wp.expired())    cout<<"监视指针已被释放"<<endl;
  • 通过lock()来获取监视的shared_ptr
std::weak_ptr<int> gw;void f(){    if (auto spt = gw.lock()) {     std::cout << *spt << "\n";    }    else {        std::cout << "gw is expired\n";    }}int main(){    {        auto sp = std::make_shared<int>(42);    gw = sp;    f();    }    f();}

输出:

42gw is expired

weak_ptr解决循环引用

将A或B改为weak_ptr即可。

struct A{    std::shared_ptr<B> bptr;    ~A()  { cout << "A is deleted!" << endl; }};struct B{    std::weak_ptr<A> aptr;    ~B()  { cout << "B is deleted!" << endl; }};void TestPtr(){    std::shared_ptr<A> ap(new A);    std::shared_ptr<B> bp(new B);    ap->bptr = bp;    bp->aptr = ap;}