智能指针auto_ptr、unique_ptr、scoped_ptr、shared_ptr、weak_ptr

智能指针auto_ptr、unique_ptr、scoped_ptr、shared_ptr、weak_ptr

我们在写代码的时候经常会发生内存泄露情况,如忘记释放堆上指针、在释放前抛出了异常、多线程情况下的问题,这些都是我们不愿意发生的,所以C++有一些用于管理内存的智能指针供我们使用,可以有效防止内存泄露的情况发生。

智能指针总体概述:

  • auto_ptr ——不推荐使用
  • shared_ptr ——引用计数智能指针,共享所有权
  • weak_ptr ——shared_ptr的观察者,只进行引用而不改变引用计数,用来解决shared_ptr的循环引用问题
  • unique_ptr ——管理单个堆内存对象,独享所有权,不允许赋值和拷贝,不能用于管理数组对象

本质
将指针封装为类对象成员,并在析构函数里删除指针指向的内存。

不同

  • auto_ptr、unique_ptr、scoped_ptr马上删除。
  • shared_ptr计数为0删除。
  • weak_ptr不删除。

1. auto_ptr

C++98标准下的智能指针

1.1 作用

对作用域内的动态分配对象的自动释放

  • 基本类型

在这里插入图片描述
作为对比:
在这里插入图片描述

1.2 缺陷

1.两个auto_ptr不能同时拥有同一个对象:

在这里插入图片描述
2.auto_ptr不能管理数组指针

#include <memory>
using namespace std;
int main(){
    int*pa=new int[10];
    auto_ptr<int>ap(pa);
}

3.auto_ptr被拷贝或被赋值后,失去对原指针的管理.这种情况被称为指针所有权传递。
在这里插入图片描述拷贝的情况
在这里插入图片描述在这里插入图片描述
4.auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等操作。

2. unique_ptr

  • 作用

C++11下用来代替auto_ptr,不能复制与赋值。

在这里插入图片描述

3. scoped_ptr

  • 作用

unique_ptr相似,在本作用域中使用,不能复制与赋值。

4. shared_ptr

C++11新添加的智能指针

  • 多个shared_ptr可以共享同一个对象,对象的最末一个拥有者有责任销毁对象,并清理与该对象相关的所有资源。
  • 一般而言,shared_ptr并非线程安全
#include <iostream>
#include <memory>
#include <string>
using namespace std;

void fun(){
    shared_ptr<string> pa(new string("CHN"));
    shared_ptr<string> pb(new string("USA"));
    cout << "*pa " << *pa << endl;//CHN
    cout << "pa.use_count " << pa.use_count() << endl;//1
    cout << "*pb " << *pb << endl;//USA
    cout << "pb.use_count " << pb.use_count() << endl;//1

    pa = pb;
    cout << *pa << endl;//USA
    cout << "pa.use_count " << pa.use_count() << endl;//2:pa和pb指向同一个资源USA了,该资源的计数为2,所以pb、pb都输出2
    cout << "pb.use_count " << pb.use_count() << endl;//2

    pa.reset();
    pb.reset();
    cout << "pa.use_count " << pa.use_count() << endl;//0
    cout << "pb.use_count " << pb.use_count() << endl;//0
}

void main()
{
    fun();
    system("pause");
}

5. weak_ptr

weak_ptr是一种用于解决shared_ptr相互引用时产生死锁问题的智能指针。如果有两个shared_ptr相互引用,那么这两个shared_ptr指针的引用计数永远不会下降为0,资源永远不会释放。weak_ptr是对对象的一种弱引用,它不会增加对象的use_countweak_ptrshared_ptr可以相互转化,shared_ptr可以直接赋值给weak_ptrweak_ptr也可以通过调用lock函数来获得shared_ptr

看两个share_ptr互相引用导致释放内存失败的例子:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

class B;
class A {
  public:
    shared_ptr<B> pb_;
    ~A() {
        cout << "A delete\n";
    }
};
class B {
  public:
    shared_ptr<A> pa_;
    ~B() {
        cout << "B delete\n";
    }
};

void fun() {
    shared_ptr<B> pb(new B());
    cout << "pb.use_count " << pb.use_count() << endl;//1
    shared_ptr<A> pa(new A());
    cout << "pa.use_count " << pa.use_count() << endl;//1

    pb->pa_ = pa;
    cout << "pb.use_count " << pb.use_count() << endl;//1
    cout << "pa.use_count " << pa.use_count() << endl;//2
    pa->pb_ = pb;
    cout << "pb.use_count " << pb.use_count() << endl;//2:由于share_ptr是共享资源,所以pb所指向的资源的引用计数也会加1
    cout << "pa.use_count " << pa.use_count() << endl;//2
}//程序结束时,没有调用A和B的析构函数

int main() {
    fun();
    return 0;
}

而使用weak_ptr:把A中的shared_ptr<B> pb_改为weak_ptr<B> pb_weak,这样改为了弱引用,传递时不会增加pb引用计数use_count()的值,所以最终能够使A、B资源正常释放:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

class B;
class A {
  public:
    weak_ptr<B> pb_weak;
    ~A() {
        cout << "A delete\n";
    }
};
class B {
  public:
    shared_ptr<A> pa_;
    ~B() {
        cout << "B delete\n";
    }
    void print() {
        cout << "This is B" << endl;
    }
};

void fun() {
    shared_ptr<B> pb(new B());
    cout << "pb.use_count " << pb.use_count() << endl;//1
    shared_ptr<A> pa(new A());
    cout << "pa.use_count " << pa.use_count() << endl;//1

    pb->pa_ = pa;
    cout << "pb.use_count " << pb.use_count() << endl;//1
    cout << "pa.use_count " << pa.use_count() << endl;//2

    pa->pb_weak = pb;
    cout << "pb.use_count " << pb.use_count() << endl;//1:弱引用不会增加所指资源的引用计数use_count()的值
    cout << "pa.use_count " << pa.use_count() << endl;//2

    shared_ptr<B> p = pa->pb_weak.lock();
    p->print();//不能通过weak_ptr直接访问对象的方法,须先转化为shared_ptr
    cout << "pb.use_count " << pb.use_count() << endl;//2
    cout << "pa.use_count " << pa.use_count() << endl;//2
}//函数结束时,正确的情况下,应该调用A和B的析构函数

/*资源B的引用计数一直就只有1,当pb析构时,B的计数减一,变为0,B得到释放,
B释放的同时也会使A的计数减一,同时pa自己析构时也会使资源A的计数减一,那么A的计数为0,A得到释放。
*/

int main() {
    fun();
    return 0;
}
  • weak_ptr接受shared_ptr类型的变量赋值,但是反过来是行不通的,需要使用lock函数。
  • weak_ptr设计之初就是为了服务于shared_ptr的,所以不增加引用计数就是它的核心功能。

weak_ptr好处:

  1. 打破递归的依赖关系
  2. 使用一个共享的资源但是不要所有权,不添加引用计数
  3. 避免悬空指针。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值