c++智能指针---shared_ptr

shared_ptr是一种智能指针,用于自动管理动态分配的对象,通过引用计数机制确保对象在不再使用时正确删除。它可以被拷贝和赋值,且在赋值时调整引用计数。使用shared_ptr可以避免手动内存管理的风险,但也需要注意在多线程环境下的同步问题。文章介绍了shared_ptr的初始化、使用方法、以及与普通指针的区别和交互。
摘要由CSDN通过智能技术生成

介绍

  • shared_ptr共享它指向的对象,多个shared_ptr可以指向(关联)相同的对象,在内部采用计数机制来实现。
  • 当新的shared_ptr与对象关联时,引用计数增加1。
  • 当shared_ptr超出作用域时,引用计数减1。当引用计数变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象。
  • 为了方便后面举例,先定义AA类
class AA
{
public:
    AA() { cout << "构造函数AA()" << endl; }
    AA(const string& name): m_name(name) { cout << "构造函数AA(" << name << ")" << endl; }
    ~AA() {cout << "析构函数~AA()" << endl; }
public:
    string m_name;
};

几种初始化方法

// 第一种,不推荐
AA *pa = new AA();
shared_ptr<AA> pu(pa);

// 第二种
shared_ptr<AA> pu(new AA());

// 第三种,C++14标准。
shared_ptr<AA> pu = make_shared<AA>("亚瑟");

shared_ptr可以拷贝与赋值

AA *pa = new AA();
shared_ptr<AA> pu_1(pa);
shared_ptr<AA> pu_2 = pu_1;	// 拷贝赋值

shared_ptr<AA> pu_3;		
pu_3 = pu_2;				// 赋值

基本使用方法

  • 智能指针重载了*和->操作符,可以像使用指针一样使用shared_ptr
shared_ptr<AA> pu(new AA("亚瑟"));
cout << pu->m_name << endl;
cout << (*pu).m_name << endl;

在这里插入图片描述

  • 通过get()获取管理的指针
shared_ptr<AA> pu(new AA("亚瑟"));
AA* pa = pu.get();

一些需要注意的地方

  1. 赋值操作时,左值的shared_ptr的计数器将减1,右值shared_ptr的计算器将加1。
shared_ptr<AA> pa0(new AA("亚瑟"));
shared_ptr<AA> pa1 = pa0;
shared_ptr<AA> pa2 = pa0;
cout << "pa0.count(): " << pa0.use_count() << endl;   // 3

shared_ptr<AA> pb0(new AA("李白"));
shared_ptr<AA> pb1 = pb0;
cout << "pb0.count(): " << pb0.use_count() << endl;   // 2

pb1 = pa0;
cout << "pa0.count(): " << pa0.use_count() << endl;   // 4,右值引用计数 +1
cout << "pb0.count(): " << pb0.use_count() << endl;   // 1,左值引用计数 -1

在这里插入图片描述

  1. nullptr给shared_ptr赋值将把计数减1,如果计数为0,将释放对象,空的shared_ptr==nullptr。
  2. std::move()可以转移对原始指针的控制权。还可以将unique_ptr转移成shared_ptr。
void test02()
{
    shared_ptr<AA> pa0(new AA("亚瑟"));
    shared_ptr<AA> pa1 = pa0;
    shared_ptr<AA> pa2 = pa0;
    cout << "pa0.count(): " << pa0.use_count() << endl;   // 3

    shared_ptr<AA> pb0(new AA("李白"));
    shared_ptr<AA> pb1 = pb0;
    cout << "pb0.count(): " << pb0.use_count() << endl;   // 2

    pb0 = std::move(pa0);	// pa0对象控制权力给pb0
    
    cout << "pa0.count(): " << pa0.use_count() << endl;   // 0
    cout << "pb0.count(): " << pb0.use_count() << endl;   // 3
}

在这里插入图片描述

  1. reset()改变与资源的关联关系。
pp.reset();        // 解除与资源的关系,资源的引用计数减1。
pp. reset(new AA("bbb"));  // 解除与资源的关系,资源的引用计数减1。关联新资源。
  1. 和普通指针一样,具备多态性质
  2. shared_ptr不是绝对安全,如果程序中调用exit()退出,全局的shared_ptr可以自动释放,但局部的shared_ptr无法释放
  3. shared_ptr提供了支持数组的具体化版本。
// shared_ptr<int[]> parr1(new int[3]);          // 不指定初始值。
shared_ptr<int[]> parr1(new int[3]{ 33,22,11 });  // 指定初始值。
cout << "parr1[0]=" << parr1[0] << endl;
cout << "parr1[1]=" << parr1[1] << endl;
cout << "parr1[2]=" << parr1[2] << endl;

shared_ptr<AA[]> parr2(new AA[3]{string("西施"), string("冰冰"), string("幂幂")});
cout << "parr2[0].m_name=" << parr2[0].m_name << endl;
cout << "parr2[1].m_name=" << parr2[1].m_name << endl;
cout << "parr2[2].m_name=" << parr2[2].m_name << endl;
  1. 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,也需要加锁保护。

使用智能指针的好处

  • 不用关心动态内存的释放问题,一般来讲,我们new出来的对象,都需要delete,但这样会存在很多潜在风险,使用shared_ptr能有效避免这些风险。

  • 不要混合使用普通指针和智能指针

void process(shared_ptr<int> ptr)
{
}// 离开作用域,ptr被销毁,计数-1

int *x = new int(200);
process(shared_ptr<int>(x));	// 内存会被释放
int j = *x;	// 错误,x是一个空悬指针

将一个临时的shared_ptr传给了process,调用结束时,临时对象被销毁,引用计数-1,变为0,所指向的内存被释放,此时x就成了空悬指针。注意:当用shared_ptr绑定了一个普通指针,我们就把内存管理的责任交给了shared_ptr,就不应该再使用普通指针来操作内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值