C++智能指针详解:原理、类型与内存泄漏处理

小岛来信
小岛来信
发布时间:2026-10-16| 5人浏览过
原创

文章详解了C++11中std::unique_ptr、std::shared_ptr和std::weak_ptr的使用场景与底层原理,通过代码示例对比展示了如何正确管理堆内存以避免常见的引用计数死锁和重复释放问题,确保程序资源安全。

为什么必须使用智能指针

C++中手动管理堆内存(new/delete)极易引发内存泄漏或重复释放错误。标准库在C++11引入了智能指针,将普通指针封装为栈对象,利用析构函数自动回收资源。

早期auto_ptr因拷贝语义缺陷已被摒弃。现代C++主要使用以下三种:

  • unique_ptr:独占所有权,防止拷贝,适用于单线程简单场景。
  • shared_ptr:共享所有权,基于引用计数,支持多线程。
  • weak_ptr:弱引用,不增加引用计数,用于解决循环引用问题。

不同智能指针的运行表现

以下是演示三种智能指针生命周期管理的完整代码:

#include <string>
#include <memory>
using namespace std;
class report {
private:
    string str;
public:
    report(const string s) : str(s) // 构造方法
    {
        cout << "1 report Object has been build!" << endl;
    }
    ~report()
    {
        cout << "3 report Object deleted!" << endl;
    }
    void talk() {
        cout << str << endl;
    }
};
int main() {
    string talk = "2 hello,this is a test!";
    {
        auto_ptr<report> ptr(new report(talk));
        ptr->talk();
    }
    {
        shared_ptr<report> ptr(new report(talk));
        ptr->talk();
    }
    {
        unique_ptr<report> ptr(new report(talk));
        ptr->talk();
    }
    return 0;
}

从运行结果可以看出,无论使用哪种智能指针,对象都在离开作用域时自动触发析构。智能指针分为两类:一类是shared_ptr可共享同一块内存,每增加一个引用计数加1;另一类是unique_ptr独占内存,所有权转移后原指针失效。

shared_ptr智能指针原理与用法

shared_ptr通过“引用计数”控制对象生命周期。初始化时计数为1,拷贝或赋值时加1,销毁时减1。当计数归零时,自动执行delete。

如何创建shared_ptr

常见的四种构造方式如下:

// 1. 空构造
shared_ptr<Object> ptr;
// 2. 直接传入裸指针
shared_ptr<Object> ptr(new Object);
// 3. 自定义删除器(Lambda表达式)
auto ptr = make_shared<Object>(args); // 最安全推荐方式
  • make_shared:一次性分配内存并构建对象,效率最高且异常安全。
  • reset():放弃当前管理权,若之前管理的对象计数降为0则会释放内存。

常用成员函数

  • use_count():返回当前引用计数的个数。
  • unique():检查是否独占资源(计数是否为1)。
  • swap():交换两个智能指针所管理的对象。
  • reset():重置指针指向或释放当前资源。

unique_ptr智能指针

unique_ptr遵循严格的所有权规则,不支持拷贝构造或赋值,但支持移动操作。这使其成为单一所有权场景下的首选,因为没有引用计数的开销,性能优于shared_ptr。

weak_ptr智能指针

weak_ptr是一种弱引用,它不控制所指对象的生命周期。它的构造和析构不会引起引用计数的增减。通常配合shared_ptr使用,用于观察对象而不参与生命周期管理。

如何处理交叉引用造成的内存泄漏

当两个shared_ptr互相指向对方时,会形成循环引用,导致引用计数永远无法归零,从而引发内存泄漏。

5.1 交叉引用场景分析

假设A类持有B的shared_ptr,B类持有A的shared_ptr。即使主函数中的局部变量销毁,由于彼此计数不为0,内存无法释放。

class B;
class A {
public:
    shared_ptr<B> _bptr;
};
class B {
public:
    shared_ptr<A> _aptr;
};

int main() {
    shared_ptr<A> aptr(new A());
    shared_ptr<B> bptr(new B());
    aptr->_bptr = bptr;
    bptr->_aptr = aptr;
    return 0;
}

5.2 解决方案

打破循环引用的最佳实践是:拥有者使用shared_ptr,被拥有者使用weak_ptr。

class A {
public:
    weak_ptr<B> _bptr; // 弱引用
};
class B {
public:
    weak_ptr<A> _aptr; // 弱引用
};

将其中一方的强引用改为弱引用后,对象的实际引用计数仅为1,当主作用域退出时,所有资源均能被正常释放。

智能指针使用注意事项

  1. 严禁混用裸指针:不要用同一个裸指针初始化多个shared_ptr,也不要使用get()获取的裸指针去创建新的智能指针,否则会导致同一块内存被重复释放。
  2. 避免手动delete:不要手动delete智能指针管理的对象或使用get()返回的指针进行释放,这会破坏引用计数逻辑。
  3. 优先使用unique_ptr:在不需共享所有权的情况下,优先选择unique_ptr以降低开销。

以上就是C++智能指针的详细内容,更多关于C++内存管理与安全编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。