C++智能指针

408 阅读2分钟

Smart Pointers 智能指针 - C++ Weekly EP3哔哩哔哩bilibili

image-20210910223754810

为什么要使用Smart Pointer

image-20210910223903398

就是new之后要不要free的麻烦,内存泄漏等问题.

引入了智能指针后,看右图:auto e = std::make_unique<Entity>(),这个相当于是new了一个Entity的指针.

std::move(e)去将这个独占的指针传给形参e,那么bar函数里面就own了e。在bar执行完后e会自动销毁,就不需要主动去free.

unique_ptr

image-20210910224529749

  • 第一句是错的,不能用一个对象的指针去赋值给智能指针.

  • 第二句是对的,但是不推荐使用.

  • 第三句是对的,推荐使用

     unique_ptr <Entity> e1 = make_unique<Entity>();
    
  • 第四句是对的,推荐使用,比第三句更简便,就是把前面的变成auto

     auto e2 = make_unique<Entity>();
    
  • 第五句是错的,unique_ptr是single ownnership,所以不能对他进行一个赋值(拷贝)

  • 第六句是对的,可以move,move就相当于是转移ownership.

     unique_ptr<Entity> e2 = move(e1);
    

    所以:

     foo(move(e1));  // 就可以成功去传参啦!
    

来看一个例子:

image-20210910225816392

 #include <memory>
 #include <string>
 #include <iostream>
 #include <cstdio>
 using namespace std;
 ​
 class Entity{
 public:
     Entity() {puts("Entity created!");}
     ~Entity(){puts("Entity destroyed!");}
 };
 ​
 void ex1(){
     puts("--------");
     puts("Entering ex1");
     {
         puts("Entering ex1::scope1");
         auto e1 = make_unique<Entity>();    // 这里创建了Entity对象
         puts("Leaving ex1::scope1");
     }
     // 这里作用域结束,就析构了这个对象,释放了指针
     puts("Leaving ex1");
 }
 ​
 void foo(unique_ptr<Entity>){
     puts("Entering foo");
     puts("Leaving foo");
 }
 ​
 void ex2(){
     puts("--------");
     puts("Entering ex2");
     auto e1 = make_unique<Entity>();    // 这里创建了Entity对象
     foo(move(e1));
     // 执行完foo函数后,就释放了
     puts("Leaving ex2");
 }
 ​
 ​
 int main()
 {
     ex1();
     ex2();
 }

image-20210910231003222

可以看出来,unique_ptr的生命周期就是在他的那个作用域结束后,unique_ptr就释放了.

image-20210910231529304

可以看到,unique_ptr是独占的,同时刻只能有一个unique_ptr去占有这个对象,然后如果需要赋值这个unique_ptr的话,就需要用move去transfer. 然后生命周期很简单,就是在他的作用域结束后终止。 比如move到了func4,然后func4结束了,就释放了.

shared_ptr

image-20210910232124391

shared_ptr的特点是,可以多个share_ptr同时共享同一个对象。 与unique_ptr一样,都是在局部作用域结束后,自动释放,不过不同的是,由于他可以多个共享,所以需要维护一个引用计数,在计数为0时才真正去删除.

  • 这个非常适合多线程程序.

image-20210910232844905

用法和unique_ptr非常像,唯一的区别在于他可以复制:

 share_ptr<Entity> e2 = e1;  

这样可以完成一个拷贝,使得shared_ptr的count+1.

来看一个例子:

image-20210910233221132

  • line38:创建了一个make_shared
  • line42:拷贝了一个shared_ptr,所以use_count +=1 ,变成了2
  • line44:将e2传递给了e3,use_count不变,这样e2就没用了(丧失了ownership) .
  • line48:离开这个作用域后,e3释放了,所以use_count -= 1, 变成了0
  • 最后,e1也退出作用域了,所以自动销毁了.

weak_ptr

image-20210910234355210

image-20210910234217766