智能指针详解


前言

智能指针本质上来讲是一个存储指向堆内存指针的类,目的就是帮助我们管理内存,一旦使用了智能指针就就尽量避免使用new产生的指针,因为智能指针只维护同类型指针的引用计数,混用很容易造成内存重复释放的问题


unique_ptr

std::unique_ptr是一种独占所有权的智能指针,它确保指向的对象只有一个所有者,并负责在其生命周期结束时自动释放对象,一块内存只能由一个unique_ptr进行管理,如果有其它的unique想要管理,就只能用move进行资源转移,它的内部计数不能超过1

使用场景:适用于管理单个所有者的对象,通常用于替代原始指针和new/delete操作。

使用方法:

  • 初始化
#include <memory>

int main() {
    std::unique_ptr<int> ptr(new int(42));
    // 使用ptr
    *ptr = 10;
    // ptr的生命周期结束时,会自动释放动态分配的内存
    return 0;
}

unique_ptr不允许复制,只能用move来移动所有权,如:

unique_ptr<int> ptr1 = move(ptr);
  • 数组
std::unique_ptr<int[]> arr(new int[size]); // 使用智能指针管理动态数组

shared_ptr

std::shared_ptr是一种共享所有权的智能指针,它允许多个std::shared_ptr指向同一个内存,通过引用计数来管理对象的生命周期,每多一个指针指向这个对象,它内部的引用计数就会加1,析构一个就减一,当引用计数为0的时候就调用它的析构函数释放这块内存

1.使用场景:适用于多个所有者的场景,允许对象被多个地方共享并且在最后一个所有者释放对象时销毁

2.使用方法:

  • 初始化
#include <memory>

int main() {
	//std::shared_ptr<int> ptr1 = new int(42);//错误,不允许用原始指针进行赋值
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);//最高效的一种初始化方法
    std::shared_ptr<int> ptr2 = ptr1; // 多个shared_ptr指向同一对象
    std::shared_ptr<int> ptr3(new int(1));//利用构造函数初始化
    // 使用ptr1和ptr2
    *ptr1 = 10;
    // 当最后一个shared_ptr被销毁时,对象会被释放
    return 0;
}
  • 管理动态数组
#include <memory>

int main() {
    int size = 10;
    std::unique_ptr<int[]> arr(new int[size]); // 使用智能指针管理动态数组

    // 对数组进行操作
    for (int i = 0; i < size; ++i) {
        arr[i] = i;
    }

    // 不需要手动释放内存,当 unique_ptr 被销毁时,动态数组内存会自动释放
    return 0;
}

3.使用注意事项:

  • 不要用一个原始指针初始化多个shared_ptr
int* ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr);//错误,应该用p1初始化p2
  • 避免循环引用
#include <memory>

class B; // 前向声明类 B

class A {
public:
    std::shared_ptr<B> b_ptr; // A 持有对 B 的 shared_ptr
};

class B {
public:
    std::shared_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr
};

int main() {
    std::shared_ptr<A> a(new A());
    std::shared_ptr<B> b(new B());

    // 循环引用
    a->b_ptr = b;
    b->a_ptr = a;

    return 0;
}

循环引用导致a和b的引用计数为2,由于释放一个 shared_ptr 时,如果其引用计数不为 1(即存在其他指针也指向同一块内存),则仅减少引用计数,而不会立即销毁管理的对象,因此离开作用域后引用计数减为1,内存泄漏,解决办法是把a和b的任意成员变量改为weak_ptr,如:

std::weak_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr

为什么引用计数开始的时候无法减为0,而用了weak_ptr就能解决问题了,这是因为weak_ptr不会增加引用计数,我画一个图来说明一下
在这里插入图片描述

weak_ptr

std::weak_ptr是一种弱引用智能指针,它允许观察std::shared_ptr指向的对象,但不会增加引用计数,也不会阻止对象的销毁。

使用场景:通常用于解决std::shared_ptr循环引用导致的内存泄漏问题,或者在需要观察对象但不需要拥有所有权的情况下使用。

使用方法:

  • 用use_count获取当前观测的资源数
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout<<wp.use_count()<<endl;
  • 用expired判断所观测的资源是否已经释放
 std::shared_ptr<A> a_ptr; // B 持有对 A 的 shared_ptr
 weak_ptr<int> wp = sp;
 if(wp.expired()){
 	cout<<"释放过了已经"<<end;
}
  • 用lock获取所监视的shared_ptr
#include <memory>

int main() {
    std::shared_ptr<int> ptr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = ptr;
    // 使用weakPtr
    if (auto sharedPtr = weakPtr.lock()) {
        // 如果对象未被释放,则获取shared_ptr并使用
        *sharedPtr = 10;
    } else {
        // 对象已经被释放
    }
    return 0;
}
  • 30
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值