0

0

如何避免智能指针的误用导致资源泄漏 常见陷阱与最佳实践

P粉602998670

P粉602998670

发布时间:2025-08-02 10:33:01

|

861人浏览过

|

来源于php中文网

原创

智能指针可能导致资源泄漏的三个主要原因是循环引用、unique_ptr所有权转移失败和自定义删除器使用不当。1. 避免shared_ptr循环引用的方法是使用weak_ptr打破循环,使其不增加引用计数;2. unique_ptr所有权转移失败常见于复制尝试、未使用std::move或返回局部unique_ptr引用,应避免这些操作;3. 使用自定义删除器时需确保其与分配方式匹配、不抛异常且线程安全,如用free_deleter释放malloc内存。

如何避免智能指针的误用导致资源泄漏 常见陷阱与最佳实践

智能指针旨在自动管理动态分配的内存,但如果使用不当,仍然可能导致资源泄漏。核心在于理解智能指针的所有权语义,并避免循环引用。

如何避免智能指针的误用导致资源泄漏 常见陷阱与最佳实践

循环引用会导致

shared_ptr
无法正确释放资源,而
unique_ptr
的不当使用则可能导致所有权转移失败。

如何避免智能指针的误用导致资源泄漏 常见陷阱与最佳实践

如何避免 shared_ptr 循环引用?

循环引用通常发生在两个或多个对象彼此持有

shared_ptr
的情况。当这些对象超出作用域时,它们的引用计数不会降为零,导致内存泄漏。

如何避免智能指针的误用导致资源泄漏 常见陷阱与最佳实践

解决方案是使用

weak_ptr
weak_ptr
是一种不增加引用计数的智能指针,它指向由
shared_ptr
管理的对象。当需要访问该对象时,可以尝试从
weak_ptr
创建一个
shared_ptr
。如果原始对象已被销毁,则创建会失败,从而避免悬挂指针。

例如:

#include 
#include 

class B; // 前向声明

class A {
public:
    std::weak_ptr b_ptr; // 使用 weak_ptr
    ~A() { std::cout << "A destroyed\n"; }
};

class B {
public:
    std::shared_ptr a_ptr;
    ~B() { std::cout << "B destroyed\n"; }
};

int main() {
    std::shared_ptr a = std::make_shared();
    std::shared_ptr b = std::make_shared();

    a->b_ptr = b;
    b->a_ptr = a;

    // 没有循环引用,A 和 B 都会被销毁
    return 0;
}

在这个例子中,

A
类使用
weak_ptr
指向
B
类的实例,避免了循环引用。当
A
B
超出作用域时,它们都会被正确销毁。如果
A
类也使用
shared_ptr
指向
B
类的实例,就会发生内存泄漏。

unique_ptr 所有权转移失败的场景有哪些?

unique_ptr
具有独占所有权,这意味着只有一个
unique_ptr
可以指向给定的资源。所有权转移必须显式进行,否则会导致
编译错误或运行时错误。

常见的错误包括:

  1. 尝试复制

    unique_ptr
    unique_ptr
    不支持复制构造函数或赋值运算符。尝试复制会导致编译错误。

    Skybox AI
    Skybox AI

    一键将涂鸦转为360°无缝环境贴图的AI神器

    下载
  2. 忘记使用

    std::move
    转移所有权: 在函数调用或赋值时,如果需要转移
    unique_ptr
    的所有权,必须使用
    std::move
    。否则,编译器会报错。

  3. 返回局部

    unique_ptr
    的引用: 返回局部
    unique_ptr
    的引用会导致悬挂引用,因为
    unique_ptr
    在函数返回时会被销毁,它所管理的资源也会被释放。

例如:

#include 
#include 

std::unique_ptr create_int() {
    std::unique_ptr ptr(new int(10));
    return ptr; // 隐式使用 move 语义
}

int main() {
    std::unique_ptr my_ptr = create_int();
    if (my_ptr) {
        std::cout << *my_ptr << std::endl;
    }

    // std::unique_ptr another_ptr = my_ptr; // 错误:尝试复制 unique_ptr
    std::unique_ptr another_ptr = std::move(my_ptr); // 正确:转移所有权

    if (my_ptr) {
        std::cout << *my_ptr << std::endl; // 不会执行,因为所有权已转移
    }

    if (another_ptr) {
        std::cout << *another_ptr << std::endl; // 输出 10
    }
    return 0;
}

如何正确使用自定义删除器避免资源泄漏?

unique_ptr
shared_ptr
都允许指定自定义删除器,用于在资源释放时执行特定的操作。如果资源不是通过
new
分配的,或者需要执行额外的清理工作,自定义删除器就非常有用。

使用自定义删除器时,需要注意以下几点:

  1. 确保删除器与资源的分配方式匹配: 如果资源是通过

    malloc
    分配的,则删除器应该使用
    free
    释放资源。如果资源是通过其他方式分配的,则删除器应该执行相应的清理操作。

  2. 避免删除器抛出异常: 如果删除器抛出异常,会导致程序终止。应该在删除器中捕获并处理任何可能发生的异常。

  3. 确保删除器是线程安全的: 如果多个线程可能同时访问同一个资源,则删除器应该是线程安全的。

例如:

#include 
#include 

// 自定义删除器,使用 free 释放资源
void free_deleter(void* ptr) {
    std::cout << "free_deleter called\n";
    free(ptr);
}

int main() {
    void* ptr = malloc(1024);
    std::unique_ptr my_ptr(ptr, &free_deleter);

    // 资源会被 free_deleter 正确释放
    return 0;
}

在这个例子中,

free_deleter
函数被用作
unique_ptr
的自定义删除器。当
my_ptr
超出作用域时,
free_deleter
会被调用,使用
free
释放
malloc
分配的内存。 如果没有使用自定义删除器,或者使用了错误的删除器(例如,使用
delete
释放
malloc
分配的内存),就会导致内存泄漏或程序崩溃。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

232

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

87

2025.10.17

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

503

2023.08.10

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

275

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.12.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

18

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

12

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Pandas 教程
Pandas 教程

共15课时 | 1.0万人学习

微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.2万人学习

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

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