避免内存泄漏及泄漏后的排查方法【C++】

内存泄漏

  • 前言
  • 编码
    • std::unique_ptr
      • 申请单个对象
      • 申请对象数组
    • std::shared_ptr
      • 申请单个对象
      • 申请对象数组
  • 编码总结

前言

最近在工作中被内存泄漏疯狂折磨,整理一下自己的思考。

编码

最近在工作中被内存泄漏疯狂折磨,我真的奉劝各位,如果你的业务代码中存在new,一定要把所有的new都干掉。已经2024年了,现在是很多程序员跟不上编译器适配新标准的节奏,而智能指针是在C++11上面就提供的特性。连 new 和 delete关键字都不要出现,因为一旦你的程序有内存泄漏,你就开始怀疑自己是不是 new 了没有 delete,这个过程非常折磨,而且肉眼去非常容易出错。我这里提供简单的实现,完全不去用 new 和 delete 关键字。

std::unique_ptr

std::unique_ptr 提供了对单个对象的独占所有权语义。
std::unique_ptr 离开作用域时,它所管理的对象会被自动销毁。

申请单个对象

#include <iostream>
#include <memory>

class MyClass 
{
public:
    MyClass(int x = 20) : value(x) { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destroyed\n"; }
    int value;
};

int main()
{
    // 对于内置基本类型
    std::unique_ptr<int> p1 = std::make_unique<int>(10); // 创建一个int对象,初始化为10
    //备注:make_unique 在C++14才支持。

    // 对于自定义类型
    std::unique_ptr<MyClass> p2 = std::make_unique<MyClass>(20); // 创建一个MyClass对象

    std::cout << *p1 << std::endl;
    std::cout << p2->value << std::endl;

    return 0;
}

运行结果:
运行结果

申请对象数组

#include <iostream>
#include <memory>

class MyClass 
{
public:
    MyClass(int x = 20) : value(x) { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destroyed\n"; }
    int value;
};

int main()
{
    // 对于内置基本类型
    std::unique_ptr<int[]> arr1 = std::make_unique<int[]>(5); // 创建一个含有5个int的数组
    // 对于自定义类型
    std::unique_ptr<MyClass[]> arr2 = std::make_unique<MyClass[]>(5); // 创建一个含有5个MyClass对象的数组

    for (int i = 0; i < 5; ++i)
    {
        std::cout << arr1[i] << " " << arr2[i].value << std::endl;
    }

    return 0;
}

运行结果:
运行结果

std::shared_ptr

std::shared_ptr 提供了共享所有权的语义,多个 std::shared_ptr 可以同时拥有同一个对象的所有权。
当最后一个拥有某个对象的std::shared_ptr被销毁时,该对象将被自动删除。

申请单个对象

#include <iostream>
#include <memory>

class MyClass 
{
public:
    MyClass(int x = 20) : value(x) { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destroyed\n"; }
    int value;
};

int main()
{
    // 对于内置基本类型
    std::shared_ptr<int> p1 = std::make_shared<int>(10); // 创建一个int对象,初始化为10

    // 对于自定义类型
    std::shared_ptr<MyClass> p2 = std::make_shared<MyClass>(20); // 创建一个MyClass对象

    std::cout << *p1 << std::endl;
    std::cout << p2->value << std::endl;
    return 0;
}

运行结果:
运行结果

申请对象数组

std::shared_ptr 没有直接支持数组的语法糖像 std::unique_ptr 那样默认情况下,std::shared_ptr 会使用 delete 而不是 delete[] 来释放它所管理的资源,这对于动态分配的数组来说是不正确的。

如果你需要使用 std::shared_ptr 管理动态数组,需要提供自定义的删除器。(不建议使用)

#include <iostream>
#include <memory>

class MyClass 
{
public:
    MyClass(int x = 20) : value(x) { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destroyed\n"; }
    int value;
};

int main()
{
    std::shared_ptr<int> arr(new int[5], std::default_delete<int[]>());
    for (int i = 0; i < 5; ++i)
    {
        arr.get()[i] = i;
        std::cout << arr.get()[i] << " ";
    }
    std::cout << std::endl;

    // 创建一个std::shared_ptr来管理MyClass的一个数组
    // 注意:使用自定义删除器来确保使用delete[]来释放数组
    std::shared_ptr<MyClass> arr2(new MyClass[5],
        [](MyClass* p) {delete[] p; });
    for (int i = 0; i < 5; ++i)
    {
        std::cout << arr2.get()[i].value << " ";
    }
    std::cout << std::endl;

    // 现在myArray智能指针负责管理这个动态分配的数组,当myArray离开作用域或被重置时,
    // 自定义删除器会被调用来正确删除数组。

    return 0;
}

运行结果:
运行结果

我们提供另外一种方式 shared + vector:

#include <iostream>
#include <memory>
#include <vector>

int main() {
    // 创建一个std::shared_ptr来管理一个std::vector<int>
    auto sharedVector = std::make_shared<std::vector<int>>();

    // 向vector中添加一些元素
    sharedVector->push_back(10);
    sharedVector->push_back(20);
    sharedVector->push_back(30);

    // 使用auto关键字遍历并打印vector的元素
    std::cout << "Vector elements: ";
    for (auto elem : *sharedVector) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // 创建一个新的shared_ptr实例,共享原有vector的所有权
    std::shared_ptr<std::vector<int>> sharedVectorCopy = sharedVector;

    // 通过共享的vector添加更多元素
    sharedVectorCopy->push_back(40);
    sharedVectorCopy->push_back(50);

    // 再次打印vector的元素,展示更改
    std::cout << "Vector elements after modification: ";
    for (auto elem : *sharedVector) {  // 注意:此处使用sharedVector或sharedVectorCopy访问的是同一个vector
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    // 当sharedVector和sharedVectorCopy都离开作用域时,
    // 它们管理的vector会被自动删除,不需要手动释放内存。

    return 0;
}

运行结果:
运行结果

编码总结

申请单个对象:std::shared_ptr ,std::unique_ptr 。
申请对象数组:std::shared_ptr + std::vector, std::unique_ptr 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466062.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

生成式 AI 术语指南:带有配图说明,没有数学公式

编者按&#xff1a; 生成式人工智能技术的发展日新月异&#xff0c;这一领域涉及到了越来越多的专业术语和概念。对于刚接触这一领域的新手来说&#xff0c;理解这些术语算是一个门槛。我们有必要整理和解释这些术语&#xff0c;帮助更多人快速入门&#xff0c;投身 AI 事业。 …

Leetcode 202.快乐数 JAVA

题目 思路 要注意题目中说的无限循环&#xff1a;它是指在求平方和的过程中&#xff0c;会再次出现之前的值&#xff08;想象一个圈&#xff09;&#xff0c;这种情况的时候肯定算不出1来。 所以我们要设定跳出循环的条件是&#xff1a;当平方和结果为1或者出现循环了 出现循…

应届生岗位直达服务

详情请私信了解 技术面试&#xff1a; C技术深入学习资源礼包&#xff08;岗位技术栈查漏补缺/非卖品&#xff09; 系统设计面试的准备 模拟技术面试和问题纠错反馈 职业发展和软技能&#xff1a; 简历优化和面试技巧 职业规划和目标设定 沟通和团队协作技能 实际…

Redis的安装和部署教程(Windows环境)

一、安装Redis服务 1、下载Redis压缩包 以下这个是我网盘里面的&#xff08;这个是v8.0版本的&#xff0c;支持导入.rdb数据文件&#xff09; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;x0f1 --来自百度网盘超级会员V5的分享 2、解压到文件夹 将下载的压缩…

NSGA-III算法:如何在多目标优化问题中找到最合适的解

当我们面临多个目标函数时&#xff0c;单目标的遗传算法可能无法满足需求。这时&#xff0c;我们可以引入多目标遗传算法。在这种情况下&#xff0c;目标函数可能存在冲突&#xff0c;例如&#xff0c;一个目标函数需要最小化&#xff0c;而另一个目标函数需要最大化。某个目标…

利用Python进行网络爬虫:Beautiful Soup和Requests的应用【第131篇—Beautiful Soup】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 利用Python进行网络爬虫&#xff1a;Beautiful Soup和Requests的应用 在网络数据变得日益丰…

基于多尺度视网膜增强图像去雾算法(MSR,Multi-Scale Retinex),Matalb实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供有偿…

Mit6.s081 前置开发环境: 虚拟机ubuntu + ssh + vscode

虚拟机 ssh vscode 前置条件 下载VMware Download VMware Workstation ProUbuntuUbuntu系统下载 | Ubuntu vscode Visual Studio Code - Code Editing. Redefined Ubuntu版本&#xff1a;20.04 Ubuntu基本操作 ubuntu 安装 ssh 服务 sudo apt-get install openssh-serv…

前端学习之css伪元素选择器

伪元素选择器 &#xff08;注释是对各个内容的解释与理解&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>伪元素选择器</title><!-- 双冒号开头一般都称为伪元素&#xff0c;…

Redis命名设计

可读性和管理性 以项目名为前缀(防止key冲突)&#xff0c;用冒号分隔&#xff0c;比如项目名:表名:id zh(知乎):news_data(新闻数据):2(主键id) zh:news_data:2 精简性 key的命名&#xff0c;尽量精简&#xff0c;key的名字长度对内存的占用不可忽视&#xff0c;我们来实际…

读者交流群

自开设公众号以来&#xff0c;收到众多读者的关注&#xff0c;所以我很高兴在这里向大家推荐加入我的技术交流群。如果你对Java和Go语言有兴趣&#xff0c;想要与其他同好分享经验和知识&#xff0c;那么这个读者群将是一个理想的选择。 在这个读者群中&#xff0c;我们有机会与…

git基础命令(四)之分支命令

目录 基础概念git branch-r-a-v-vv-avv重命名分支删除分支git branch -h git checkout创建新的分支追踪远程分支同时切换到该分支创建新的分支并切换到该分支撤销对文件的修改&#xff0c;恢复到最近的提交状态&#xff1a;丢弃本地所有修改git checkout -h git merge合并指定分…

docker 安装minio,详细图解

废话不多说&#xff0c;直接上干货 docker 安装minio 拉取镜像 docker pull minio/minio创建数据目录、配置目录 mkdir /opt/minio/data mkdir /opt/minio/config启动容器 docker run -p 9000:9000 -p 9090:9090 \--name minio \-d --restartalways \-e "MINIO_ACCESS_KE…

[全网首发中文版]LLM4Decompile: Decompiling Binary Code with Large Language Models

LLM4Decompile: Decompiling Binary Code with Large Language Models 摘要 反编译的目的是将编译后的代码恢复为人类可读的源代码&#xff0c;但在名称和结构等细节上遇到了困难。 大型语言模型&#xff08;大语言模型&#xff09;显示出编程任务的前景&#xff0c;激励其应…

如何用大模型做出一款属于自己的 AI 应用?

语言模型是怎么回事 语言模型&#xff08; language model&#xff0c;LM &#xff09;简单来说&#xff0c;就是利用自然语言构建的模型。 自然语言就是我们日常生活、学习和工作中常用的文字。语言模型就是利用自然 语言文本构建的&#xff0c;根据给定文本&#xff0c;输出…

jquery 合并单元格

原始表格 合并后的单元格 直接上代码 //合并第一列单元格//给tbody下的第一行(tr:first-child)第一个单元格(td).eq(0))//加上rowspan 长度是这个表格tr的长度(attr(rowspan, $("tbody tr").length);)$(tbody tr:first-child td).eq(0).attr(rowspan, $("t…

idea2023 运行多 springboot 实例

概要 1、修改idea运行多实例&#xff08;本地测试负载&#xff09; 你可能用到其他 1、改造项目缓存token 至redis 支持负载均衡部署 SpringSecurity6.0RedisJWTMP基于token认证功能开发&#xff08;源码级剖析可用于实际生产项目&#xff09;_springsecurity redis管理token…

算法导论第十二章练习参考答案(22) - 12.1-12.4

Exercise 12.1-1 任何时候&#xff0c;如果一个节点有一个子节点&#xff0c;就把它当作右子节点&#xff0c;左子节点为NIL。 Exercise 12.1-2 二叉搜索树的属性保证了左子树的所有节点都更小&#xff0c;右子树的所有节点都更大。最小堆属性只保证一般的子节点大于父节点的关…

3.18 杂题小结

类似的对于n个物体根据其某种递减关系选择的题目可以利用数位 &#xff1a;当前字符可以选也可以不选 &#xff01;&#xff1a;当前字符无法选 思路&#xff1a;需要同一位置多次比对的一般使用动态规划&#xff08;背包中物品是否拿取、字符串取舍与修改方式等&#xff09;…

2024华为OD统一考试(C卷)最新题库(Java Python C++)

关于华为OD ​ 华为的员工补充途径有三种&#xff0c;分别是校招、OD转正和社招。校招是华为唯一的正式员工入职途径&#xff0c;但是从近几届开始竞争非常激烈&#xff0c;尤其是在CV、AI、NLP等赛道上&#xff0c;所以对于C9等专业的学生来说&#xff0c;可以考虑转向一些冷…