【C++新特性】智能指针

370 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

【C++新特性】智能指针

std::weak_ptr

std::weak_ptr是一种弱引用,它不能单独使用,设计之初是为了配合std::shared_ptr,解决后者的问题。

  • 使用注意:

    • 不能直接指向原始指针:std::weak_ptr<int> wp (new int);
    • 只能指向std::shared_ptr对象或者std::weak_ptr对象
    • 不增加引用计数
    • 可以用expired()来检测指向的std::shared_ptr管理的对象是否被析构了。
    • 不能直接使用std::shared_ptr管理的对象,如果要使用需要调用lock()。如果底层的对象还没被析构,那么就会返回一个std::shared_ptr指针,指向该对象,否则返回nullptr
  • 构造函数

         constexpr weak_ptr() noexcept;
     ​
         weak_ptr( const weak_ptr& r ) noexcept;
         weak_ptr( weak_ptr&& r ) noexcept;
     ​
         template< typename Y >
         weak_ptr( const weak_ptr<Y>& r ) noexcept;
         
         template< typename Y >
         weak_ptr( weak_ptr<Y>&& r ) noexcept;
     ​
         template< typename Y >
         weak_ptr( const std::shared_ptr<Y>& r ) noexcept;
    

    从构造函数可见,std::weak_ptr只能接受std::weak_ptrstd::shared_ptr类型,而不能std::weak_ptr<T> wp (new T);

    移动语义下的构造函数,构造完成 r 将会变成 nullptr ,不可用。

  • 函数

  • std::weak_ptr 主要有两个用途: 它只能配合std::shared_ptr使用,不能单独使用。

    • 防止 std::shared_ptr循环引用 如果两个std::shared_ptr相互引用,那么就会形成一个环,引用计数无法变成0,也会导致内存泄漏。

    • std::enable_shared_from_this<T>::shared_from_this 什么情况下需要使用 *shared_from_this() *??? 用于返回当前对象 *thisstd::shared_ptr类型指针时:

           class Foo : public enable_shared_from_this<Foo>{
           public:
               Foo(){ 
                   std::cout<<"Foo ctor.\n";
               }
               ~Foo(){
                   std::cout<<"Foo dtor.\n";
               }
               
               std::shared_ptr<Foo> getSelf(){ 
                   return shared_from_this();
               }
           };
           
           int main() {
               Foo* foo = new Foo; 
               std::shared_ptr<Foo> sp1(foo);
               std::shared_ptr<Foo> sp2 = sp1->getSelf();  // 为了对 foo对象进行共享
               
               std::cout<<std::boolalpha;
               std::cout<<(sp2.get()== foo)<<std::endl;
               std::cout<<sp1.use_count()<<std::endl;
           } 
      

      函数原型

           template<typename _Tp>
           class enable_shared_from_this {
           protected:
               ...
           public:
               shared_ptr<_Tp>
               shared_from_this() { 
                   return shared_ptr<_Tp>(this->_M_weak_this); 
               }
       ​
               shared_ptr<const _Tp>
               shared_from_this() const { 
                   return shared_ptr<const _Tp>(this->_M_weak_this); 
               }
           private:
               ...
               mutable weak_ptr<_Tp>  _M_weak_this;
           }
      

      enable_shared_from_this的子类需要返回自身的std::shared_ptr指针,那么就需要继承这个类。

      • 成员变量为什么是weak_ptr类型 因为如果是std::shared_ptr类型,那么就永远无法析构对象自身。

        这个_M_weak_this不是这个类中初始化,而是在shared_ptr中初始化,初始化的值就是this。因此如果智能指针类型是std::shared_ptr,那么这个类对象一旦创建,引用计数就是1,那么永远也无法析构。

      • 为什么不直接传回this std::shared_ptr的引用计数增加是需要用operator=实现的。

             class Foo {/** ... */};
             
             int main() {
                 Foo* foo = new Foo;
                 std::shared_ptr<Foo> sp1(foo);
                 std::shared_ptr<Foo> sp2(foo);
                 std::cout<<sp1.use_count()<<std::endl; // 输出是1
             }  
        

        也就是说,尽管sp1sp2都指向了foo,但是却不共享计数,当析构的时候就会被析构两次,产生未定义行为。 std::weak_ptr可以接受std::shared_ptr参数来构造自己,std::shared_ptr也具有接受std::weak_ptr参数来构造自己。