0

0

C++智能指针shared_ptr用法详解_C++内存管理与避免内存泄漏

尼克

尼克

发布时间:2025-12-29 15:34:02

|

142人浏览过

|

来源于php中文网

原创

std::shared_ptr是C++11引入的智能指针,通过引用计数自动管理内存,防止泄漏;支持多实例共享对象所有权,引用计数为0时自动释放资源。使用make_shared创建更安全高效,避免裸指针直接构造。引用计数操作线程安全,但对象访问需额外同步。循环引用会导致内存泄漏,可用std::weak_ptr打破循环。支持自定义删除器处理文件、数组等特殊资源。建议优先使用make_shared,避免重复释放和异常风险,结合unique_ptr与weak_ptr构建安全资源管理体系。

c++智能指针shared_ptr用法详解_c++内存管理与避免内存泄漏

在C++开发中,内存管理是核心问题之一。手动管理内存容易导致内存泄漏、重复释放或悬空指针等问题。为了解决这些问题,C++11引入了智能指针,其中 std::shared_ptr 是最常用的智能指针之一,它通过引用计数机制自动管理对象的生命周期,有效避免内存泄漏。

什么是 shared_ptr?

std::shared_ptr 是一个模板类,用于共享某个堆上对象的所有权。多个 shared_ptr 实例可以指向同一个对象,内部维护一个引用计数。每当有新的 shared_ptr 指向该对象时,引用计数加1;当某个 shared_ptr 被销毁或重新赋值时,引用计数减1。当引用计数变为0时,表示没有指针再使用该对象,系统会自动调用其析构函数并释放内存。

这种机制确保了资源在不再被任何所有者使用时才被释放,从而防止内存泄漏。

基本用法与创建方式

使用 shared_ptr 前需包含头文件:

立即学习C++免费学习笔记(深入)”;

#include

推荐使用 std::make_shared 创建 shared_ptr,这是最安全和高效的方式:

auto ptr1 = std::make_shared(42);
auto ptr2 = ptr1; // 引用计数变为2

也可以用普通构造函数绑定已有的指针,但应尽量避免直接传入裸指针,以防异常导致泄漏:

int* raw = new int(10);
std::shared_ptr ptr3(raw); // 不推荐,除非必要

更安全的做法始终是优先使用 make_shared,它能保证原子性地分配对象和控制块,性能更好且异常安全。

引用计数与线程安全

shared_ptr 的引用计数操作是线程安全的:多个线程同时拷贝或销毁不同的 shared_ptr 实例(指向同一对象)不会导致数据竞争。但注意,这仅指控制块的引用计数本身安全,并不保护所指向对象的数据同步。

举例说明:

std::shared_ptr globalPtr = std::make_shared();

// 线程1
auto p1 = globalPtr; // 安全:增加引用计数

// 线程2
auto p2 = globalPtr; // 安全:同样增加引用计数

虽然引用计数安全,但若多个线程通过 p1p2 同时修改 *p1 或 *p2 所指内容,仍需额外同步机制(如互斥锁)保护对象本身。

循环引用问题与 weak_ptr 解决方案

使用 shared_ptr 最常见的陷阱是循环引用:两个对象互相持有对方的 shared_ptr,导致引用计数永远无法归零,造成内存泄漏。

LLaMA
LLaMA

Meta公司发布的下一代开源大型语言模型

下载

例如:

struct Node {
    std::shared_ptr parent;
    std::shared_ptr child;
};

auto a = std::make_shared(); // 引用计数=1
auto b = std::make_shared(); // 引用计数=1
a->child = b;
b->parent = a; // 循环形成:a 和 b 的引用计数都为2

ab 离开作用域时,它们的引用计数从2降到1,但由于彼此持有,无法继续下降到0,内存不会释放。

解决办法是使用 std::weak_ptr 打破循环。它不增加引用计数,仅观察对象是否存在:

struct Node {
    std::shared_ptr child;
    std::weak_ptr parent; // 改为 weak_ptr
};

访问 weak_ptr 时需先检查对象是否还存在:

if (auto p = b->parent.lock()) {
    // p 是 shared_ptr,可安全使用
}

这样,当外部指针释放后,对象能被正确回收。

自定义删除器

有时需要释放非标准资源,比如文件句柄、C风格数组或调用特定清理函数。shared_ptr 支持传入自定义删除器:

void close_file(FILE* f) {
    if (f) fclose(f);
}

auto fp = std::shared_ptr(fopen("data.txt", "r"), close_file);

fp 被销毁时,会自动调用 close_file 函数关闭文件。删除器也可为 lambda 表达式,灵活适配各种场景。

对于动态数组,虽然 C++ 推荐使用 std::vectorstd::array,但如果必须使用原始数组,可通过删除器指定 delete[]:

auto arr = std::shared_ptr(new int[10], [](int* p){ delete[] p; });

不过更现代的写法仍是优先选择容器类型。

常见使用建议

  • 优先使用 std::make_shared 创建对象,避免多次内存分配和异常风险。
  • 不要将同一个裸指针多次交给不同的 shared_ptr,会导致重复释放。
  • 避免在函数参数中直接调用 make_shared,以防异常导致临时对象未被保存。
  • 在可能形成循环引用的场景中,使用 weak_ptr 打破强依赖。
  • 理解引用计数的开销,在高性能或频繁复制场景中评估是否适合使用。

基本上就这些。合理使用 shared_ptr 可显著提升代码的安全性和可维护性,是现代 C++ 内存管理的重要工具。配合 unique_ptrweak_ptr,能够构建清晰、低风险的资源管理体系。不复杂但容易忽略的是循环引用和删除器细节,多加留意即可避免大部分问题。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

709

2023.08.22

fclose函数的用法
fclose函数的用法

fclose是一个C语言和C++中的标准库函数,用于关闭一个已经打开的文件,是文件操作中非常重要的一个函数,用于将文件流与底层文件系统分离,释放相关的资源。更多关于fclose函数的相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

321

2023.11.30

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

311

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

515

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

48

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

188

2025.08.29

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

172

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

92

2025.11.27

ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

121

2025.12.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.5万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 18.4万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号