C++ 11 STL智能指针的基本使用

在C++中解决内存泄漏的有效方法是使用智能指针(Smart Pointer)。智能指针和普通指针的用法类似,只是不需要手动释放内存,而是通过智能指针自己管理内存释放。
智能指针是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保在离开指针所在作用域时,自动正确的销毁动态分配的对象,防止内存泄漏。它的一种通用
实现技术是使用引用计数,每使用它一次,内部的引用计数加1,每析构一次,内部引用计数减1,减为0时,删除所指向的堆内存。

C++11 提供了3种智能指针:std::shared_ptr、std::uniq_ptr、std::weak_ptr,头文件为<memory>

一、shared_ptr 共享的智能指针:
  一:初始化:
  通过 构造函数、std::make_shared<T>辅助函数、reset方法来初始化shared_ptr,优先使用make_shared来构造智能指针
  std::shared_ptr<int> p(new int(1));
  std::shared_ptr<int> p2=p;
  std::shared_ptr<int> ptr;
  ptr.reset(new int(1));

  对于一个未初始化的智能指针,可以通过reset方法来初始化。
  当智能指针中有值的时候,调用reset会使引用计数减1,
  通过重载bool类型操作符来判断智能指针中是否为空

  获取原始指针:当需要获取原始指针时,可以通过get方法来返回原始指针
  std::shared_ptr<int> ptr(new int(1));
  int *p=ptr.get();
  二:删除共享指针
  (1)删除指针:
    (1)指定删除器:当p的引用计数为0时,自动调用删除器DeleteIntPtr 来释放对象的内存
    void DeleteIntPtr(int* p)
    {
      delete p;
    }
    std::shared_ptr<int> p(new int,DeleteIntPtr); //当p的引用计数为0了,就销毁p
    (2)
    lambda表达式也可以    
    std::shared_ptr<int> p(new int,[](int *p){delete p;});

  (2)删除数组指针
    (1)shared_ptr管理动态数组时,需要强制指定删除器,默认的删除器不支持数组删除指针。
    std::shared_ptr<int> p(new int[10],[](int *p){delete[] p;});
  
    (2)
    void DeleteIntPtr(int* p[])
    {
      delete[] p;
    }
    (3)std::shared_ptr<int> p(new int[],DeleteIntPtr); //当p的引用计数为0了,就销毁p
  
    (4)也可以将std::default_delete 作为删除器。default_delete的内部是通过调用delete来实现功能的:推荐
    std::shared_ptr<int> p(new int[10],std::default_delete<int[]>);

注意:
(1) 不能将一个原始指针直接赋值给一个智能指针
    std::shared_ptr<int> p=new int(1);//编译报错,不允许直接赋值
(2) 不要用一个原始指针初始化多个shared_ptr,例如下面这些事错误的
    int *ptr=new int;
    shared_ptr<int> p1(ptr);
    shared_ptr<int> p2(ptr);//logic error
(3) 不要在函数实参中创建shared_ptr
    function (shared_ptr<int> (new int),g());//有缺陷
    正确的写法应该是先创建智能指针:    shared_ptr<int> p(new int());   f(p,g());
(4) 通过shared_from_this()返回this指针。不要将this指针作为shared_ptr返回出来,因为this指针本质上是一个裸指针,因此,这样可能会导致重复析构。
    shared_ptr<A> GetSelf()
   {
       return shared_ptr<S>(this);//不要这样做!!!
   }
   正确做法:让目标类通过派生std::enable_shared_from_this<T>类,然后使用基类的成员函数shared_from_this来返回shared_ptr
   class A:public std::enable_shared_from_this<A>
   {
    public:
      std::shared_ptr<A> GetSelf()
      {
        return shared_from_this();
      }
    };
    std::shared_ptr<A> spy(new A);
    std::shared_ptr<A> p=spy->GetSelf();  //正确

(5) 要避免循环引用。智能指针最大的一个陷阱是循环引用,循环引用会导致内存泄露:
    class A
    {
        std::shared_ptr<B> bptr;
        ~A(){cout<<"A is deleted!"<<endl;}
    };
    class 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;
        }
}
//解决方式,在类A、类B中生命的shared_ptr指针有一个为弱引用指针weak_ptr ,即可解决问题 
二、unique_ptr 独占的智能指针
  unique_ptr是一个独占型的智能指针,它不允许其他智能指针共享其内部的指针.
  1、初始化  
  (1)不允许通过赋值将一个unique_ptr赋值给另外一个unique_ptr。
        unique_ptr<T> myPtr(new T);
        unique_ptr<T> myOtherPtr=myPtr;//错误!! 不能复制
  (2)unique_ptr不允许复制,可以通过函数返回给其他的unique_ptr,可以通过std::move来转移到其他的unique_ptr,之后它就不在拥有原来指针的所有权.
        unique_ptr<T> myPtr(new T); //OK
        unique_ptr<T> myOtherPtr=std::move(myPtr);//OK
  (3)unique_ptr除了独占性这个特点之外,还可以指向一个数组
        std::unique_ptr<int []> ptr(new int[10]);
        ptr[9]=9;//设置最后一个元素为9
  2、删除指针,指定删除器
  (1)std::unique_ptr指定删除器的时候需要确定删除器的类型
        std::unique_ptr<int,std::function<void(int*)>> ptr(new int(1),[&](int* p){delete p;});
  (2)自定义unique_ptr的删除器
        void Deleter(Connection *connection)
        {
            delete connection;
        }
        unique_ptr<Connection, decltype(Deleter)*> up(new Connection("unique_ptr"), Deleter);
        另一种使用方法:
        class CConnnect
        {
            void Disconnect() { PRINT_FUN(); }  
        };
        class Deleter
        {
        public:
            void operator() (CConnnect* obj)
            {
                delete obj;
            }
        };
        std::unique_ptr<CConnnect, Deleter> up2(new CConnnect, up1.get_deleter());
三、weak_ptr 弱引用的智能指针
  弱引用指针weak_ptr是用来监视shared_ptr的,不会使引用计数加1,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命周期,
  更像是shared_ptr的一个助手
  (1)初始化:
      1:通过use_count()方法来获得当前观测资源的引用计数.
        shared_ptr<int> sp(new int(10));
        weak_ptr<int> wp(sp);
        cout<<wp.use_count()<<endl;//结果将输出1
      2:通过expired()方法来判断所观测的资源是否已被释放.
        shared_ptr<int> sp(new int(10));
        weak_ptr<int> wp(sp);
        if(wp.expired())
        {
          std::cout<<"weak_ptr 无效,所监视的智能指针已被释放"<<endl;
        }
        else
        {
            std::cout<<"weak_ptr有效"<<endl;
        }
        //结果输出:weak_ptr有效
      3:通过lock方法来获取所监视的shared_ptr.
        std::weak_ptr<int> gw;
        void f()
        {
          if(gw.expired())//所监视的shared_ptr是否释放
          {
              std::cout<<"gw is expired"<<endl;
          }
          else
          {
              auto spt=gw.lock();
              std::cout<<*spt<<endl;
          }
        }

        int main()
        {
          {
              auto sp=std::make_shared<int>(42);
              gw=sp;
              f();
          }
          f();
        }
        //输出:42  gw is expired
      4:weak_ptr返回this指针
        提到不能直接将this指针返回为shared_ptr,需要通过派生std::enable_shared_from_this类,
        并通过其他方法shared_form_this来返回智能指针,因为std::enable_shared_from_this类中有一个weak_ptr,这个weak_ptr用来观测this智能指针,
        调用shared_from_this()方法时,会调用内部这个weak_ptr的lock方法,将所观测的shared_ptr返回.
      5:weak_ptr 解决循环引用问题
            class A
            {
               std::shared_ptr<B> bptr;
                ~A(){cout<<"A is deleted!"<<endl;}
            };
            class 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;
                }
            }
  (3)
  (4)
  (5)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值