博客
关于我
【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/

你可能感兴趣的文章
计算机网络基础:NAT 网络地址转换
查看>>
计算机网络基础:PKI(公钥基础设施)
查看>>
计算机网络基础:VLAN(虚拟局域网)
查看>>
计算机网络基础:文件共享服务器(注册表更改)
查看>>
计算机网络基础:用户和组管理
查看>>
计算机网络基础:简单渗透
查看>>
计算机网络模型-TCP/IP协议簇
查看>>
基于Arduino的ESP32-S3 + OLED(4pin)的文字取模
查看>>
基于Arduino的ESP32-S3 + 1.3寸OLED(4pin)
查看>>
基于Arduino的ESP32-S3连接OneNET云平台实战指南(二)——Token生成
查看>>
基于Arduino的ESP32-S3连接OneNET云平台实战指南(四)——ESP32-S3连接OneNET云平台的订阅主题与发布主题、消息(数据流)
查看>>
基于Arduino的ESP32-S3 + HCSR04(4pin)超声波传感器
查看>>
乒乓球问题
查看>>
线程、多线程和线程池面试专题
查看>>
Trae国内版发布,中国首款AI 原生IDE 正式上线,配置Doubao-1.5-pro,支持切换满血版DeepSeek 模型
查看>>
java定时器,留着用
查看>>
多线程,高并发
查看>>
linux(CENTOS)系统各个目录的作用详解
查看>>
科技前沿:React 组件之间通信的新模式与实践
查看>>
PHP实现异步定时多任务消息推送
查看>>