智能指针

智能指针


C++11 种提供了3种智能指针,使用时需要包含头文件

  • std::shared_ptr: 共享智能指针
  • std::unique_ptr: 独享的智能指针
  • std::weak_ptr: 弱引用的智能指针,不共享指针,不操作资源,用来监视shared_ptr

shared_ptr

1、shared_ptr 的初始化

​ 提供四种方式来进行初始化:

  • 通过构造函数初始化, 如

    std::shared_ptr<int> ptr1(new int); // 
    std::shared_ptr<int > ptr2(new T()); //构造的同时,完成初始化内存;
    
        shared_ptr<int> ptr1(new int);
        shared_ptr<int> ptr2(new int(123));
    
        cout << ptr1.use_count() << " ptr1 value:"<< *ptr1 << "\n" << ptr2.use_count() << " ptr2 value:"<< *ptr2<< endl;
    		// 输出:1 ptr1 value:0
    						1 ptr2 value:123
    
    • 注意事项

      • 可以初始化为空
      shared_ptr<int> ptr;  // 不管理任何内存,use_count = 0;
      
      • shared_ptr ptr3 = new int(123); //error, 将调用拷贝构造函数,拷贝构造函数是explicit的.
      • 可以初始化为空指针
      shared_ptr<int> ptr(nullptr);
      
  • 通过拷贝和移动构造函数初始化

        shared_ptr<int> ptr1(new int(123));
        shared_ptr<int> ptr2(ptr1);    // 调用拷贝构造函数
        shared_ptr<int> ptr3 = ptr1;   // 调用拷贝构造函数
        shared_ptr<int> ptr4(move(ptr3)); // 调用移动构造函数
        shared_ptr<int> ptr5 = move((ptr4)); // 调用移动构造函数
    
        cout << ptr1.use_count() << endl;
        cout << ptr3.use_count() << endl;
        cout << ptr4.use_count() << endl;
        cout << ptr5.use_count() << endl;
        //cout << *ptr4 << endl; // Segmentation fault, 已经不具有所有权
        
        //输出:
        3 0 0 3
    
  • 通过make_shared 初始化

    class A {
    public:
        A() {
            cout << "default construct" << endl;
        }
        A(int x) {
            cout << "int default construct" << endl;
        }
    
        A(string str) {
            cout << "string default construct" << endl;
        }
    
        ~A() {
            cout << "deconstruct ~" << endl;
        }
    };
    
    void test03() {
        shared_ptr<int> ptr1 = make_shared<int>(520);
        cout << ptr1.use_count() << endl;
    
        shared_ptr<A> ptr2 = make_shared<A>();
        shared_ptr<A> ptr3 = make_shared<A>(1);
        shared_ptr<A> ptr4 = make_shared<A>("abc");
    
    }
    // 输出
    1
    default construct
    int default construct
    string default construct
    deconstruct ~
    deconstruct ~
    deconstruct ~
    
  • 通过reset来初始化,对于一个未初始化的共享智能指针,可以通过reset方法来初始化,当智能指针中有值的时候,调用reset会使引用计数减1。

    void test04() {
    
        shared_ptr<int> ptr;
        ptr.reset(new int(123));
        cout << *ptr << endl;
    
        shared_ptr<int> ptr2 = make_shared<int>(1);
        shared_ptr<int> ptr3 = ptr2;
    
        ptr2.reset();
        cout << ptr3.use_count() << " "<< ptr2.use_count() << endl;
        cout << *ptr3 << endl;
       // cout << *ptr2 << endl;  //段错误,已经释放对内存的管理权
    }
    //输出
    123
    1 0
    1
    
2、原始指针
  • 通过get() 获取,

  • 可以通过release() 返回原始对象的指针

    std::shared_ptr<int> ptr(new int(42));
    int* rawPtr = ptr.release(); //释放指针并返回指向的内存地址
    //现在,rawPtr指向原始内存,并且ptr不再管理该内存
    delete rawPtr; //手动释放内存
    
3、reset()
  • 使用该函数,引用计数减1, 不会再指向这个对象
4、release()
  • release()方法返回当前shared_ptr中的指针,并将shared_ptr重置为空指针。这意味着shared_ptr不再管理该内存区域,并且不会自动删除该内存。
5、指定删除器
  • 当管理动态数组内存时,需要指定删除器

    void deleteInt(int* p) {
        delete []p;
        cout << "delete" << endl;
    }
    
    void test06() {
        shared_ptr<int> ptr(new int[10], deleteInt);
        shared_ptr<int> ptr2(new int[10], [](int* p) {
            delete []p;
            cout << "lambda delete" << endl;
        });
    }
    //输出
    lambda delete
    delete
    
  • 使用默认的删除器

    shared_ptr<int> ptr(new int[10], default_delete<int[]>());
    

unique_ptr()

​ unique_ptr是一个独占型的智能指针,不允许其他的智能指针共享内部的指针,不允许拷贝构造

1、初始化
  • 初始化示例

        unique_ptr<int> ptr(new int(10));
        //unique_ptr<int> ptr2 = ptr ; // error
    
  • 虽然不允许复制, 但是可以通过函数返回unique_ptr,也可以通过move转移

        unique_ptr<int> ptr1(new int(10));
        unique_ptr<int> ptr2 = move(ptr1);
    
        unique_ptr<int> ptr3 = func();
    
2、获取原始指针
  • get()
3、reset()
  • 解除对内存的管理

        unique_ptr<int> ptr1(new int(10));
        unique_ptr<int> ptr2 = move(ptr1);
    
        //cout << *ptr1 << endl; //Segmentation fault 已经释放,
    
        ptr1.reset();
        ptr2.reset(new int(20));
    
4、指定删除器
  • unique_ptr和shared_ptr指定删除器是有区别的,unique_ptr指定删除器需要确定删除器的类型

          shared_ptr<int> ptr1(new int[10], [](int* p) {delete []p;}) ;// error
    
        //unique_ptr<int> ptr1(new int[10], [](int* p) {delete []p;}) // error
        using func_ptr = void(*)(int *);
        unique_ptr<int, func_ptr> ptr2(new int[10], [](int* p) {delete []p;});
    
  • 指定删除器有4种方法

    • 函数指针

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

      上面写法没有在lambda中捕获变量,如果捕获将编译错误

      std::unique_ptr<int[], void(*)(int *)> ptr(new int[10], [&](int *p) {delete p; }); // error
      
    • functional

          unique_ptr<int, function<void(int*)> > ptr1(new int[10], [&](int*p) {delete []p;cout << "functional delete" << endl;});
      
      
    • 使用仿函数

      struct funDelete{
        void operator()(int* p) {
            delete[] p;
            cout << "funDelete " << endl;
        }
      };
      
      void test06() {
          unique_ptr<int, funDelete> p(new int[10]);
      }
      
    • 默认删除器default_delete

      unique_ptr<int[]> ptr(new int[10], default_delete<int[]>());
      

weak_ptr()

​ weak_ptr不管理shared_ptr内部的指针,没有重载操作符* 和->, 不共享指针,不能操作资源,它的构造不会增加引用计数,析构不会减少引用计数,主要是监视shared_ptr中管理的资源是否存在。

1、初始化
  • 可以通过shared_ptr来构造

    shared_ptr<int> ptr(new int(10));
    weak_ptr<int> ptr2 = ptr;
    
  • 构造空的weak_ptr

     weak_ptr<int> wp1;
     weak_ptr<int> wp2(wp1);
    
2、use_count()
  • 获取管理对象的引用计数,只监视,不管理资源
3、expired()
  • 判断所观测的资源是否已经被释放,true表示已经释放, false表示没有被释放
4、lock()
  • 通过lock 方法获取shared_ptr对象

        shared_ptr<int> ptr = make_shared<int>(10);
        weak_ptr<int> wptr;
        wptr = ptr;
        shared_ptr<int> sp2 = wptr.lock();
        cout << sp2.use_count() << endl;
        
        //输出
        2
    
5、reset()
  • 清空对象,使不监测任何资源

        shared_ptr<int> ptr = make_shared<int>(19);
        weak_ptr<int> wptr = ptr;
        wptr.reset();
        cout << wptr.expired() << endl;
        cout << *ptr << endl;
    
    // 输出
    1
    19
    
6、循环引用问题
  • shared_ptr 如果循环引用,可能导致内存泄露,所以引入weak_ptr

    struct B;
    
    struct A {
        shared_ptr<B> mPtrB;
        ~A() {
            cout << "delete A" << endl;
        }
    };
    
    struct B {
        shared_ptr<A> mPtrA;
        ~B() {
            cout << "delete B" << endl;
        }
    };
    
    void test04() {
        shared_ptr<A> ptra(new A);
        shared_ptr<B> ptrb(new B);
        ptra->mPtrB = ptrb;
        ptrb->mPtrA = ptra;
    
        cout << ptra.use_count() << " " << ptrb.use_count() << endl;
    
    }
    // 输出2 2
    
  • 改成weak_ptr

    struct B;
    
    struct A {
        shared_ptr<B> mPtrB;
        ~A() {
            cout << "delete A" << endl;
        }
    };
    
    struct B {
        weak_ptr<A> mPtrA;
        ~B() {
            cout << "delete B" << endl;
        }
    };
    
    void test04() {
        shared_ptr<A> ptra(new A);
        shared_ptr<B> ptrb(new B);
        ptra->mPtrB = ptrb;
        ptrb->mPtrA = ptra;
    
        cout << ptra.use_count() << " " << ptrb.use_count() << endl;
    
    }
    //输出
    1 2
    delete A
    delete B
    
7、shared_from_this()
  • 当一个类被共享智能指针 share_ptr 管理,且在类的成员函数里需要把当前类对象作为参数传给其他函数时,这时就需要传递一个指向自身的 share_ptr

    #include <iostream>
    #include <memory>
    using namespace std;
    
    struct Test : public enable_shared_from_this<Test>
    {
        shared_ptr<Test> getSharedPtr()
        {
            return shared_from_this();
        }
        ~Test()
        {
            cout << "class Test is disstruct ..." << endl;
        }
    };
    
    int main() 
    {
        shared_ptr<Test> sp1(new Test);
        cout << "use_count: " << sp1.use_count() << endl;
        shared_ptr<Test> sp2 = sp1->getSharedPtr();
        cout << "use_count: " << sp1.use_count() << endl;
        return 0;
    }
    // 输出
    use_count: 1
    use_count: 2
    class Test is disstruct ...
    
  • 需要使用的原因:

    #include <iostream>
    #include <memory>
    
    class Widget{
    public:
        Widget(){
            std::cout << "Widget constructor run" << std::endl;
        }
        ~Widget(){
            std::cout << "Widget destructor run" << std::endl;
        }
    
        std::shared_ptr<Widget> GetSharedObject(){
            return std::shared_ptr<Widget>(this);
        }
    };
    
    int main()
    {
        std::shared_ptr<Widget> p(new Widget());
        std::shared_ptr<Widget> q = p->GetSharedObject();
    
        std::cout << p.use_count() << std::endl;
        std::cout << q.use_count() << std::endl;
    
        return 0;
    }
    // 输出
    Widget constructor run
    1
    1
    Widget destructor run
    Widget destructor run
    // 会析构两次
    

补充

  • shared_ptr 自身引用计数是线程安全的,但是指向的数据并不是线程安全的

  • unique_ptr没有use_count()函数。

参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值