C++的内存管理
内存分布高地址 ↑ ├─────────────┤ │ 栈 │ ← 向下增长局部变量、函数参数 ├─────────────┤ │ │ │ │ ↓ │ ├─────────────┤ │ 内存映射段 │ ← 共享库、共享内存 ├─────────────┤ │ ↑ │ │ │ │ ├─────────────┤ │ 堆 │ ← 向上增长动态分配 ├─────────────┤ │ 数据段 │ ← 全局变量、静态变量 ├─────────────┤ │ 代码段 │ ← 可执行代码、常量 └─────────────┘ 低地址 includeiostream using namespace std; int globalVar 1; // 全局变量 static int staticGlobalVar 1; // 静态全局变量 void Test() { static int staticVar 1; // 静态局部变量 int localVar 1; // 局部变量 int num1[10] {1, 2, 3, 4}; // 局部数组 char char2[] abcd; // 局部数组存储字符串的副本 const char* pChar3 abcd; // 指针变量指向常量字符串 int* ptr1 (int*)malloc(sizeof(int) * 4); // 动态分配 int* ptr2 (int*)calloc(4, sizeof(int)); // 动态分配 int* ptr3 (int*)realloc(ptr2, sizeof(int) * 4); // 重新分配 free(ptr1); free(ptr3); // 注意ptr2被realloc处理了不需要再free } int main() { Test(); return 0; }说明栈又叫做堆栈——存储非静态局部变量/函数参数/返回值等向下增长内存映射段是高效的I/O映射方式用于装载一个共享的动态内存库。堆是用于内存的动态内存分配向上增长系统一般给的内存都比较大数据段用于存储全局变量和静态变量代码段用于可执行的代码/只读常量动态内存管理malooc/calloc/realloc的区别#includeiostream using namespace std; void Test() { // 1. malloc - 分配未初始化的内存 int* p1 (int*)malloc(sizeof(int) * 4); if (p1 NULL) { perror(malloc fail); return; } // 2. calloc - 分配并初始化为0 int* p2 (int*)calloc(4, sizeof(int)); // calloc(4, sizeof(int)) 等价于 malloc(4 * sizeof(int)) 内存置0 // 3. realloc - 调整已分配内存的大小 int* p3 (int*)realloc(p2, sizeof(int) * 10); // 注意如果realloc成功p2会被自动处理不需要free(p2) if (p3 NULL) { free(p2); // realloc失败时原内存不变需要手动释放 return; } // 释放内存 free(p1); free(p3); // p2已经被realloc处理不需要单独free }内存管理方式C语言的内存管理方式在C也可以使用但是也有一些欠缺点用起来比较麻烦。因此C有自己新的内存管理方式——通过操作符new和delete用法讲解#includeiostream using namespace std; int main() { // 1. 基本用法申请和释放单个对象 int* p1 new int; // 申请一个 int未初始化 int* p2 new int[10]; // 申请 10 个 int 的数组未初始化 delete p1; // 释放单个对象 delete[] p2; // 释放数组 // 2. 初始化用法申请时初始化 int* p3 new int(0); // 申请一个 int初始化为 0 int* p4 new int[10]{ 0 }; // 申请 10 个 int全部初始化为 0 int* p5 new int[10]{ 1, 2, 3, 4, 5 }; // 前5个初始化后面默认为0 delete p3; // 释放单个对象 delete[] p4; // 释放数组 delete[] p5; // 释放数组 return 0; }注意new 和 delete 必须配对使用new - deletenew[] - delete []应用示例struct ListNode { int val; ListNode* next; ListNode(int x) : val(x) , next(nullptr) {} }; int main() { // 1. 自定义类型 A 的 new/delete假设 A 存在 // A* p1 new A; // 调用默认构造 // A* p2 new A(1); // 调用带参构造 // delete p1; // delete p2; // 2. 创建链表节点 ListNode* n1 new ListNode(1); ListNode* n2 new ListNode(2); ListNode* n3 new ListNode(3); ListNode* n4 new ListNode(4); // 3. 连接节点形成链表 n1-next n2; n2-next n3; n3-next n4; n4-next nullptr; // 尾节点指向 nullptr已经由构造函数设置 // 4. 遍历链表 ListNode* cur n1; while (cur ! nullptr) { cout cur-val - ; cur cur-next; } cout nullptr endl; // 5. 释放链表内存重要 cur n1; while (cur ! nullptr) { ListNode* next cur-next; // 保存下一个节点 delete cur; // 释放当前节点 cur next; // 移动到下一个 } return 0; }可以看到写链表的时候可以直接传参初始化不需要写Init。从应用层面我们可以看到创造new和delete的原因是为了给自定义类型使用的因为自定义类型往往都需要调用默认构造函数更为方便对应内置类型和malloc和free的区别不大自定义类型int main() { // 1. 单个对象使用 new 申请并构造 A* p1 new A(1); // 调用 A(int) 构造函数 A* p2 new A(2, 2); // 调用 A(int, int) 构造函数 // 2. 对象数组使用已有对象拷贝构造 A aa1(1, 1); A aa2(2, 2); A aa3(3, 3); A* p3 new A[3]{ aa1, aa2, aa3 }; // 调用拷贝构造 // 3. 对象数组使用临时对象 A* p4 new A[3]{ A(1, 1), A(2, 2), A(3, 3) }; // 4. 对象数组使用聚合初始化C11 列表初始化 A* p5 new A[3]{ {1, 1}, {2, 2}, {3, 3} }; // 释放内存 delete p1; delete p2; delete[] p3; delete[] p4; delete[] p5; return 0; }具体用法详解对单个对象class A { public: A(int x) : _a(x) { cout A(int) 构造 endl; } A(int x, int y) : _a(x), _b(y) { cout A(int,int) 构造 endl; } ~A() { cout ~A() 析构 endl; } private: int _a; int _b; }; int main() { // 1. 单个对象调用构造函数 A* p1 new A(10); // 调用 A(int) A* p2 new A(20, 30); // 调用 A(int, int) // 2. 释放单个对象调用析构函数 delete p1; // 先调用 ~A()再释放内存 delete p2; return 0; }对象数组int main() { // 方式1默认构造需要 A 有默认构造 A* p1 new A[3]; // 调用 3 次默认构造 // 方式2使用已有对象拷贝构造 A a1(1, 1), a2(2, 2), a3(3, 3); A* p2 new A[3]{ a1, a2, a3 }; // 调用 3 次拷贝构造 // 方式3使用临时对象 A* p3 new A[3]{ A(1, 1), A(2, 2), A(3, 3) }; // 方式4列表初始化C11 A* p4 new A[3]{ {1, 1}, {2, 2}, {3, 3} }; // 释放数组必须用 delete[] delete[] p1; // 先调用 3 次析构再释放内存 delete[] p2; delete[] p3; delete[] p4; return 0; }关键点——new和delete的底层调用的是operatror new和operator deletenew的执行过程A* p new A(1, 2); // 执行步骤 // 1. 调用 operator new 分配内存类似 malloc // 2. 在分配的内存上调用 A 的构造函数 // 3. 返回指向该对象的指针 new A(1, 2) │ ├─ 1. 调用 operator new (全局函数) │ │ │ └─ 调用 malloc() 分配原始内存 │ │ │ ├─ 成功 → 返回内存地址 │ └─ 失败 → 执行用户设置的应对措施 │ └─ 仍失败 → 抛出 bad_alloc 异常 │ ├─ 2. 在分配的内存上调用 A 的构造函数 │ └─ A::A(1, 2) 初始化对象 │ └─ 3. 返回指向构造完成的对象的指针delete的执行过程delete p; // 执行步骤 // 1. 调用 p 指向对象的析构函数 // 2. 调用 operator delete 释放内存类似 free delete p │ ├─ 1. 调用 p 指向对象的析构函数 │ └─ A::~A() 清理对象资源 │ └─ 2. 调用 operator delete (全局函数) │ └─ 调用 free() 释放原始内存new[]和delete[]的执行过程A* p new A[3]{ A(1,1), A(2,2), A(3,3) }; // 执行步骤 // 1. 分配能容纳 3 个 A 对象的内存 额外空间存储数组大小 // 2. 按顺序调用 3 次构造函数 delete[] p; // 执行步骤 // 1. 按逆序调用 3 次析构函数先析构最后一个 // 2. 释放内存注意事项new和delete的配对// 错误 A* p1 new A(1); delete[] p1; // 错误单个对象不能用 delete[] A* p2 new A[3]; delete p2; // 错误数组必须用 delete[] // 正确 A* p1 new A(1); delete p1; A* p2 new A[3]; delete[] p2;自定义类型必须要有正确的构造函数class B { public: B(int x) : _x(x) {} // 只有带参构造没有默认构造 private: int _x; }; int main() { B* p1 new B(10); // 可以 // B* p2 new B; // 错误没有默认构造 // B* p3 new B[3]; // 错误数组需要默认构造 delete p1; return 0; }内存泄漏问题/ 内存泄漏 void BadFunction() { A* p new A(1); // 没有 delete p函数结束导致内存泄漏 } // 正确 void GoodFunction() { A* p new A(1); delete p; } // 更好使用智能指针 #includememory void BestFunction() { unique_ptrA p make_uniqueA(1); // 自动释放 }关于operator new 和 operator deletevoid* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { void* p; // 尝试分配内存 while ((p malloc(size)) 0) { // 如果分配失败执行用户设置的 new_handler if (_callnewh(size) 0) { // 用户没有设置应对措施或措施失败抛出异常 static const std::bad_alloc nomem; _RAISE(nomem); } } return p; } void operator delete(void* pUserData) { if (pUserData NULL) return; // 直接调用 free 释放内存 free(pUserData); }核心newoperator new分配内存构造函数delete析构函数operator delete释放内存new[]operator new[]分配内存N次构造函数delete[]N次析构函数operator delete[]释放内存

相关新闻

C++ Boost.Beast 自定义 Body:零拷贝与流式处理

C++ Boost.Beast 自定义 Body:零拷贝与流式处理

本文深入 Boost.Beast 的 Body 体系,讲解 BodyReader/BodyWriter 概念要求,实现一个自定义 Body,并详解 http::buffer_body 的零拷贝流式用法。所有 API 均对照 Beast 官方文档与头文件源码核实。 这是 Boost.Beat 系列的最难一篇,涉及 Beast 的核心扩展机制。 一、为什么需…

2026/8/8 12:10:42 阅读更多 →
架构设计之Redisson分布式锁-自定义大注解(十)

架构设计之Redisson分布式锁-自定义大注解(十)

摘要:本文是架构设计系列第十篇,深入剖析 Redisson 分布式锁的核心原理与实战开发。我们将从基础概念出发,逐步讲解 Redisson 的锁机制、WatchDog 自动续期、可重入锁、公平锁、联锁、红锁等高级特性,并重点实现一套基于自定义注解…

2026/8/7 9:13:08 阅读更多 →
拆解 OpenStack 虚拟网络!Neutron 底层原理 + OVN 组网实操

拆解 OpenStack 虚拟网络!Neutron 底层原理 + OVN 组网实操

OpenStack管理 摘要:本文系统介绍了OpenStack网络管理组件Neutron的核心原理与实践。首先对比物理网络与虚拟网络,阐述Neutron对二层物理网络的抽象与管理。接着详细讲解Linux网络虚拟化关键技术,包括网卡虚拟化(TAP/TUN/VETH&…

2026/8/8 12:10:42 阅读更多 →

最新新闻

企业微信API自动加好友,10分钟搞定

企业微信API自动加好友,10分钟搞定

把重复的加好友动作交给API处理,减少人工操作成本 能力介绍 在日常运营中,加好友是一个非常高频但重复的动作。通过API配合RPA自动化能力,可以实现自动触发加好友流程,例如根据外部数据、任务规则或事件条件,自动完成…

2026/8/8 12:10:22 阅读更多 →
Windows文件搜索太慢?EverythingToolbar让你在任务栏实现秒级文件查找

Windows文件搜索太慢?EverythingToolbar让你在任务栏实现秒级文件查找

Windows文件搜索太慢?EverythingToolbar让你在任务栏实现秒级文件查找 【免费下载链接】EverythingToolbar Everything integration for the Windows taskbar. 项目地址: https://gitcode.com/gh_mirrors/eve/EverythingToolbar 你是否曾因Windows自带的文件…

2026/8/8 12:10:22 阅读更多 →
Linux文件大小统计:高效命令与实用技巧

Linux文件大小统计:高效命令与实用技巧

1. 项目概述 在日常Linux系统管理和开发工作中,我们经常需要统计一组文件的总大小。无论是清理磁盘空间、分析存储占用,还是进行备份规划,快速准确地获取文件集合的总容量都是基础而重要的操作。本文将深入解析几种高效计算文件总大小的方法&…

2026/8/8 12:10:22 阅读更多 →
微信聊天记录永久保存终极指南:如何用WeChatMsg轻松备份你的数字记忆

微信聊天记录永久保存终极指南:如何用WeChatMsg轻松备份你的数字记忆

微信聊天记录永久保存终极指南:如何用WeChatMsg轻松备份你的数字记忆 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Tre…

2026/8/8 12:10:22 阅读更多 →
容器化部署性能优化实战:从资源分配到网络调优

容器化部署性能优化实战:从资源分配到网络调优

1. 容器化部署性能优化实战解析最近在帮客户做容器化迁移时遇到一个典型案例:某电商平台的促销系统在传统虚拟机环境下运行良好,但迁移到容器环境后,在流量高峰时段频繁出现响应延迟和OOM(内存不足)问题。经过两周的调…

2026/8/8 12:10:22 阅读更多 →
客户一多就忙不过来?很多人用API做自动化了

客户一多就忙不过来?很多人用API做自动化了

把重复的客户操作交给程序处理,人只关注关键环节 能力介绍 当客户数量上来之后,很多操作都会变成重复劳动,比如:加好友、发消息、打标签、跟进记录等。如果全部依赖人工,不仅效率低,还容易遗漏。 通过API结…

2026/8/8 12:09:22 阅读更多 →

日新闻

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

当下AI应用飞速普及,无数企业下场搭建智能体系统,可落地阶段难题接踵而至:上下文无限堆积频繁爆栈、AI工具调用准确率低下、Token成本居高不下、企业数据权限混乱暗藏安全隐患……很多团队卡在架构搭建环节,空有前沿技术概念&…

2026/8/8 0:00:07 阅读更多 →
PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码 【免费下载链接】php-qrcode A PHP QR Code generator and reader with a user-friendly API. 项目地址: https://gitcode.com/gh_mirrors/ph/php-qrcode 在当今数字时代,二维码已…

2026/8/8 0:00:08 阅读更多 →
UniApp微信小程序隐私保护组件开发:从原理到实战

UniApp微信小程序隐私保护组件开发:从原理到实战

1. 项目缘起:为什么我们需要一个隐私保护通用组件?最近在维护一个基于uniapp开发的微信小程序矩阵时,我遇到了一个非常棘手的问题。随着平台对用户隐私保护的要求越来越严格,几乎每一个新版本发布,或者在某些特定机型&…

2026/8/8 0:00:08 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/6 22:02:27 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/8 8:58:26 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/7 23:24:08 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/7 17:02:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/7 23:54:54 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/7 17:02:36 阅读更多 →