博客
关于我
【C++】智能指针详解及原理简单说明
阅读量:496 次
发布时间:2019-03-07

本文共 4352 字,大约阅读时间需要 14 分钟。

智能指针:C++内存管理的利器

一、智能指针前提知识

智能指针(Smart Pointer)是一种用于管理动态内存的工具,能够自动释放资源,避免内存泄漏和错误操作。传统内存管理方式容易导致资源泄漏或双重释放等问题,而智能指针通过 RAII(资源 管理即初始化)原理,利用对象生命周期来管理资源。

为什么需要智能指针?

  • 在C++中进行动态内存申请时,容易忘记调用 delete,甚至在异常发生时也无法保证资源的释放。
  • mallocnew 分配的空间如果未正确释放,会导致内存泄漏,影响程序性能和安全性。

简单理解内存泄漏

  • 操作过程中未经释放的动态内存,导致应用程序失去对该空间的控制权。
  • 频繁分配空间但无释放,会造成内存碎片化问题。

内存泄漏分类

  • 堆内存泄漏:未释放通过 newmallocrealloc 分配的空间。
  • 系统资源泄漏:未释放系统分配的资源,如套接字、文件描述符。

内存泄漏解决方案

  • 事前预防型:如智能指针,确保最后自动释放资源。
  • 事后查错型:使用泄漏检测工具,定期检查内存状况。

二、智能指针的原理

智能指针通过 RAII 原理,利用对象的生命周期管理资源。其行为类似于指针,支持普通指针的操作,如 *->

RAII:利用对象生命周期

RAII(Resource Acquisition Is Initialization)是一种资源管理方法,强制将资源与对象的生命周期绑定。资源通过对象的构造函数获取,对象的析构函数负责释放资源。

典型实现:auto_ptr

auto_ptr 是 C++11 标新引入的智能指针类型,采用资源转移实现。

  • 拷贝构造函数:浅拷贝会释放目标对象的资源,导致双重释放错误。
  • 资源转移:通过将资源转移到新对象,确保资源只被一个对象持有,最终由最后 one 使用对象释放。

auto_ptr 实现代码

template
class auto_ptr {public: auto_ptr(t* ptr = nullptr) : _ptr(ptr) {} ~auto_ptr() { if (_ptr) { delete _ptr; _ptr = nullptr; } } t& operator*() { return *_ptr; } t* operator->() { return _ptr; } template
auto_ptr(auto_ptr
& other) : _ptr(other._ptr) { other._ptr = nullptr; } template
auto_ptr& operator=(auto_ptr
& other) { if (this != &other) { if (_ptr) delete _ptr; _ptr = other._ptr; other._ptr = nullptr; } return *this; }private: t* _ptr;};

auto_ptr 的缺点

  • 不支持成数组内存管理。
  • 不能直接管理由 freemalloc 分配的内存。
  • 同时引用同一对象的 auto_ptr 会导致行为错误。

三、unique_ptr

unique_ptrauto_ptr 的改进版,采用资源独占方式。

资源独占

  • 一个资源只能被一个 unique_ptr 管理。
  • 拷贝或移动 unique_ptr 会将资源释放,依据新获取的对象进行资源管理。

定制删除器

template
class Delete {public: void operator()(t* p) { if (p) { delete p; p = nullptr; } }};// 简单实现template
class unique_ptr {public: unique_ptr(t* ptr = nullptr) : _ptr(ptr) {} ~unique_ptr() { if (_ptr) DF df(_ptr); delete _ptr; _ptr = nullptr; } template
unique_ptr(unique_ptr
& other) = delete; template
unique_ptr& operator=(unique_ptr
& other) = delete; t& operator*() { return *_ptr; } t* operator->() { return _ptr; }private: t* _ptr;};

unique_ptr 的优点

  • 提供更强的资源管理控制。
  • 可以直接管理 mallocreallocfree 分配的内存。

四、shared_ptr

shared_ptr 是以引用计数方式管理共享资源的智能指针。

原理

  • 引用计数:允许多个对象共享同一资源,最终由最后 one 拥有的对象释放资源。
  • 链接存储:个旧对象的引用计数减一,若减为零,则转移到新的对象。

语义示例

#include 
#include
std::shared_ptr
sp1(new int(42));std::shared_ptr
sp2(sp1);std::cout << sp1.use_count() << std::endl; // 输出 1std::cout << sp2.use_count() << std::endl; // 输出 1sp2 = std::shared_ptr
(new int(10));std::cout << sp1.use_count() << std::endl; // 输出 1std::cout << sp2.use_count() << std::endl; // 输出 1

shared_ptr 是否支配资源?

bool own = std::shared_ptr
::owns_ptr(sp_np);

五、weak_ptr

用于解决 shared_ptr 在循环引用中的引用计数异常增大问题。

目的

  • 允许一定程度的循环引用,同时保持资源释放的正确性。
  • 适用于 DOM 结构、图,等需要广泛共享的场景。

实现方式

  • 引用计数:与 shared_ptr 类似,但引用计数较低。
  • 共享器媒体:自身可以作为 shared_ptr 的来源。

使用场景示例

class Node {public:    Node(int data) : left(nullptr), right(nullptr) {}    virtual ~Node() {}    template
Node& operator<<(T&& t) { this->data = std::move(t); return *this; } Node* left; Node* right; int data;};

weak_ptr 实现示例

template+='
'class weak_ptr {public: weak_ptr(t* ptr = nullptr) : _ptr(ptr) {} template
weak_ptr(weak_ptr
& other) : _ptr(other._ptr) {} template
weak_ptr& operator=(weak_ptr
& other) { if (this != &other) { _ptr = other._ptr; } return *this; } t* operator*() { return _ptr; } t* operator->() { return _ptr; } int use_count() { return _pCount; } bool unique() { return _pCount == 0; }private: t* _ptr; int* _pCount;};

如何解决循环引用问题

  • 使用 weak_ptr 为节点对象管理指针,避免循环引用导致的高引用计数。
struct Node {    Node(int value) : left(nullptr), right(nullptr) {}    template
Node& operator<<(T&& val) { this->value = val; return *this; } weak_ptr
left; weak_ptr
right; int value;};

六、总结

智能指针通过 RAII 原理,大大简化了内存管理,减少了内存泄漏和错误的风险。在实际应用中,根据资源管理需求选择合适的智能指针类型,如 unique_ptrshared_ptrweak_ptr,以确保程序的稳定性和安全性。

转载地址:http://dsacz.baihongyu.com/

你可能感兴趣的文章
00013.05 字符串比较
查看>>
Effective Java 读书笔记
查看>>
访问servlet时弹出文件下载框解决方法
查看>>
IDEA-@Slf4j和log标签&@Data(Lombok)无效
查看>>
SpringCloud-Eureka报错 Error creating bean with name解决
查看>>
Thymeleaf 生成下标,索引,使用Stat变量
查看>>
初始微服务---Springcloud发展【第一期】
查看>>
RAFT 拜占庭将军 共识算法
查看>>
UE4 错误列表 error码(只记录我遇到的情况,持续添加,未完成)
查看>>
cmd编译.java文件 : java:720: 错误: 编码GBK的不可映射字符 Why ? ? ? ?
查看>>
Android 架构组件 – 让天下没有难做的 App
查看>>
能解决数据可视化大屏需求的3款可视化工具
查看>>
多代理区块链框架客户端的操作
查看>>
一些技术博客
查看>>
第01问:MySQL 一次 insert 刷几次盘?
查看>>
优先级队列2
查看>>
TiKV 源码解析系列文章(十三)MVCC 数据读取
查看>>
Android 开发常用的工具类(更新ing)
查看>>
HTTP 错误 500.21 - Internal Server Error 发布网站遇到这个错误
查看>>
初次安装webpack之后,提示安装webpack-cli
查看>>