C++智能指针详解

1. 为什么需要智能指针?

看下面的例子:

在这里插入图片描述
若p1处new抛异常,则相当于p1的new没有成功,则什么都不用做
在这里插入图片描述
若p2处new抛异常,则相当于p2的new没有成功,而p1的new成功了,所以需要释放p1,然后再重新抛出
在这里插入图片描述
若div处抛异常,则将p1与p2都释放,再将其重新抛出

可以看出处理起来非常麻烦,存在内存泄漏的问题(只进行new,但没有delete)
第二个new抛异常要释放第一个new,div抛异常要释放前两个new
若再添加一个new,则又会存在new抛异常的问题,还需添加 try catch

为了提前预防内存泄漏的问题,就提出了智能指针

2. 智能指针的使用

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
不需要显式地释放资源
对象所需的资源在其生命期内始终保持有效

RAII是一种思想,智能指针是这种思想的产物

智能指针的常见问题

1.使用对象的生命周期去控制资源

在这里插入图片描述
创建一个私有的成员变量 _ptr指针
在构造函数时,将指针保存起来
在析构函数时,将指针释放

将申请的资源,交给智能指针对象去管理
(通过这个指针 去构造一个智能指针对象,这个对象会把指针保留起来)
在这里插入图片描述
创建对象时,会调用构造函数,将new int 传给类中的指针,对象会把指针保留起来
v1和v2属于局部对象,出了作用域时,就会调用析构函数 ,完成释放

若第一个new抛异常,就不会进入构造函数中
若第二个new抛异常,则调用析构,将第一个new释放掉
若div抛异常,则v1和v2对象都调用析构,将第一个new和第二个new都释放掉

通过类的构造和析构的自动调用,利用对象的生命周期来管理资源,被称之为 RAII

2. 像指针一样使用

在这里插入图片描述
在类中实现 operator() 和operator->,使对象可以进行解引用 和->访问成员的操作

3. 拷贝问题

因为没有在类中实现拷贝构造,默认是浅拷贝 ,所以就会导致释放两次,从而报错

深拷贝是不可以的,因为指针拷贝要的就是浅拷贝

链表等迭代器 结构与智能指针类似,用的是浅拷贝,为什么没有问题?
因为迭代器不管资源的释放,资源释放是容器处理的
智能指针需要管资源释放,所以不能单纯的浅拷贝

auto_ptr ——管理权转移

当上述v1和v2都管理这个资源就会有问题,两者都会去释放,导致释放两次

所以C++98版本的库中就提供了auto_ptr的智能指针,提出了 管理权转移的思想
将管理权只给一个对象,剩下一个对象去除管理权

如果不了解管理权转移的特性,但管理权转移,存在被拷贝对象悬空的问题

unique_ptr ——防拷贝

使用禁止生成默认函数的关键字 delete

在这里插入图片描述

shared_ptr (根本解决拷贝问题)

特点为使用引用计数,支持拷贝
在这里插入图片描述

有两个对象指向资源,当析构时,会析构两次
为了解决这个问题,就增加一个引用计数,若只有一个对象,就为1,若为两个对象,则为2
在这里插入图片描述
当其中一个对象要析构时,就先看引用计数,若引用计数减1还大于0,就要什么都不管
若引用计数减1为0

### C++ 智能指针详解 #### 定义与作用 智能指针是一种类模板,用于管理动态分配的对象生命周期。通过自动处理对象的创建和销毁,智能指针能够有效防止内存泄漏和其他资源管理错误。 #### 类型介绍 C++标准库提供了三种主要类型的智能指针: - **unique_ptr** `std::unique_ptr` 是一种独占所有权的智能指针,不允许复制操作,但支持移动语义[^1]。 ```cpp std::unique_ptr<int> ptr(new int(10)); ``` - **shared_ptr** `std::shared_ptr` 实现了引用计数机制,允许多个指针共享同一个对象实例。当最后一个指向该对象的 `shared_ptr` 被销毁或重置时,所管理的对象也会被删除[^2]。 ```cpp auto sptr = std::make_shared<int>(20); ``` - **weak_ptr** `std::weak_ptr` 不增加引用计数,通常作为辅助工具配合 `shared_ptr` 使用,主要用于解决循环引用问题[^3]。 ```cpp std::weak_ptr<int> wptr(sptr); ``` #### 应用场景示例 假设有一个简单的工厂模式实现,其中涉及到了不同种类的产品生产。为了简化代码并提高安全性,可以采用智能指针来代替原始裸指针。 ```cpp #include <memory> #include <iostream> // 基础产品接口定义 struct Product { virtual ~Product() {} virtual void use() const = 0; }; // 具体产品的实现之一 struct ConcreteProductA : public Product { void use() const override { std::cout << "Using product A\n"; } }; // 工厂函数返回智能指针而非普通指针 std::unique_ptr<Product> create_product_a() { return std::make_unique<ConcreteProductA>(); } int main() { // 自动管理内存,无需手动delete auto prod = create_product_a(); prod->use(); return 0; } ``` 上述例子展示了如何利用 `std::unique_ptr` 来安全地管理和传递堆上分配的对象,而不需要担心忘记释放资源的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值