C++内存管理——malloc/free和new/delete
(注:该文章只讲解了C++手动管理内存的方式,自动管理方式也就是智能指针在新特性栏目中,感兴趣的小伙伴可以去了解,非常感谢)
目录
3、全局 / 静态存储区(Global/Static Storage)
C++ 提供了多种内存管理方式,包括传统的 C 风格的 malloc 和 free,以及 C++ 专用的 new 和 delete。
理解这些内存管理方法对于编写高效、安全的 C++ 程序至关重要。
一、❤️了解内存分区
C++ 程序运行时的内存主要分为以下几个区域,各自有不同的生命周期和用途:
1、✨栈(Stack)
- 特性:自动管理内存,存储局部变量和函数调用信息。内存分配和释放速度快,但空间有限。
- 存储内容:函数参数、局部变量、返回地址等
- 大小:通常较小,由系统自动管理
- 示例:
void func() { int a = 10; // 存储在栈上,函数结束后自动释放 double b; // 栈上分配 }
2、✨堆(Heap)
- 特性:动态分配与释放,需要程序员手动管理(或通过智能指针自动管理),灵活但易出错(如内存泄漏、悬挂指针)。
- 存储内容:程序运行时动态创建的对象 / 数据
- 大小:较大,生命周期由开发者控制
- 示例:
int* p = new int(5); // 堆上分配int delete p; // 手动释放
3、✨全局 / 静态存储区(Global/Static Storage)
- 特性:程序启动时分配,程序结束时释放
- 存储内容:全局变量、静态变量(
static修饰) - 示例:
int global_value = 20; // 全局变量 void func() { static int static_value; // 静态局部变量 }
4、✨常量存储区(Constant Storage)
- 特性:存储常量,不可修改,程序结束时释放
- 示例:
const int MAX = 100; // 常量 char* str = "hello"; // "hello"存储在常量区
5、✨代码区(Code Segment)
- 特性:存储程序的二进制指令,只读
- 作用:确保程序指令不会被意外修改
二、❤️C语言风格的内存管理:
✨malloc函数
malloc(memory allocation)用于在堆上分配指定字节数的内存。
其函数原型:
void * malloc(size_t size);
- 参数:
size指要分配的内存字节数。 - 返回值:指向分配内存的指针,如果分配失败则返回
nullptr。 - 功能:从堆中分配一块连续的、大小为
size字节的内存块。 - 特点:
- 只负责分配内存,不初始化内存
- 返回
void*类型,需显式转换为目标指针类型。
✨free函数
free 用于释放之前由 malloc、calloc 或 realloc 分配的内存。
其函数原型:
void free(void* ptr);
- 参数:
ptr指要释放的内存指针。 - 功能:释放
malloc(或calloc/realloc)分配的内存块,归还给系统。 - 特点:
- 只释放内存,不销毁对象(因为C 语言中无 “对象” 概念,仅仅释放原始内存)。
- 释放后指针变为 “悬空指针”,建议置为
nullptr避免误用。 - 不能释放非
malloc分配的内存(如栈内存),否则会导致未定义行为。
- 其他配套函数:
calloc(size_t num, size_t size):分配num个大小为size的内存块,并初始化为 0。realloc(void* ptr, size_t size):调整已分配内存块的大小,可能移动内存位置。
示例:
#include <iostream>
#include <cstdlib> // 包含 malloc 和 free
int main() {
// 分配一个整数的内存
int* p = (int*)malloc(sizeof(int));
if (p == nullptr) {
std::cerr << "memory allocation failed" << std::endl;
return 1;
}
*p = 42;
std::cout << "value: " << *p << std::endl;
// 释放内存
free(p);
p = nullptr; // 避免悬空指针
return 0;
}
注意事项:
- 类型转换:
malloc分配内存成功,返回void*,所以需要显式转换为所需类型的指针。 - 初始化:
malloc分配的内存未初始化,内容是不确定的。 - 释放必须对应:由
malloc分配的内存必须使用free释放,而不是使用delete。
三、❤️C++的内存管理:
C++ 在 C 的基础上扩展了内存管理,new/delete不仅管理内存,还与对象的生命周期绑定(调用构造 / 析构函数)。
✨new操作符
- 功能:从堆中分配内存,并自动调用对象的构造函数初始化。
- 特点:
- 无需显式指定内存大小(由对象类型自动推导)。
- 无需类型转换(返回对应类型的指针)。
- 分配失败时抛出
std::bad_alloc异常(默认行为),或返回nullptr(但是需指定nothrow)。 - 支持数组分配(
new[])和定位new(在已分配内存中构造对象)。
✨delete操作符
- 功能:用于释放由
new分配的内存,先调用对象的析构函数销毁对象,再释放内存。 - 特点:
- 必须与
new配对使用(delete[]与new[]配对)。 - 释放数组时必须用
delete[],否则只会调用第一个元素的析构函数,导致内存泄漏。 - 释放后指针变为悬空指针,建议置为
nullptr。
- 必须与
示例:
#include <iostream>
class Dog {
public:
Dog() {
std::cout << "have a dog..." << std::endl;
}
~Dog() {
std::cout << "dog is died..." << std::endl;
}
};
int main() {
// 分配单个对象:内存分配 + 构造函数调用
int* num = new int(10); // 分配int并初始化为10
Dog* dog = new Dog(); // 分配Dog对象并调用其构造函数
// 分配数组:内存分配 + 每个元素的构造函数调用
int* arr = new int[5] {1, 2, 3, 4, 5}; // C++11起支持初始化列表
Dog* dogs = new Dog[3]; // 调用了3次Dog构造函数
// 不抛异常的分配方式
int* p = new (std::nothrow) int; // 失败时返回nullptr
// 释放单个对象:析构函数调用 + 内存释放
delete num; // 对于基础类型,仅释放内存(没有析构函数)
delete dog; // 调用Dog析构函数,再释放内存
// 释放数组:每个元素析构 + 内存释放
delete[] arr; // 释放int数组(基础类型无析构)
delete[] dogs; // 调用3次Dog析构函数,再释放内存
num = nullptr; // 避免悬空指针
}
输出:
have a dog...
have a dog...
have a dog...
have a dog...
dog is died...
dog is died...
dog is died...
dog is died...
四、❤️malloc/free与new/delete的核心差异
|
维度 |
|
|
|
操作对象 |
原始内存块(无 “对象” 概念) |
对象(内存分配 + 构造 / 析构) |
|
初始化 |
不初始化内存(内容随机) |
自动调用构造函数初始化(基础类型可显式初始化) |
|
类型处理 |
返回 |
自动匹配类型,无需转换 |
|
大小指定 |
需手动传入字节数 (如 |
由类型自动推导,无需指定 |
|
异常处理 |
失败返回 |
失败默认抛出 ,可指定 |
|
数组支持 |
需手动计算总大小 ( |
直接用 |
|
与类的交互 |
不调用构造 / 析构函数(无法管理对象生命周期) |
自动调用构造 / 析构函数(核心差异) |
|
重载支持 |
不能重载 |
可以重载(自定义内存分配逻辑) |
五、❌常见错误与注意事项
1.🥀 混用malloc与delete
❌错误示例:
int* p = (int*)malloc(sizeof(int));
delete p; // 错误:malloc分配的内存不能用delete释放
原因:malloc仅分配内存,delete会尝试调用析构函数(对基础类型无影响,但对类对象会出错)。
2. 🥀混用new与free
❌错误示例:
Dog* dog = new Dog();
free(dog); // 错误:new分配的内存不能用free释放
原因:free不会调用析构函数,导致对象资源未释放(内存泄漏)。
3. 🥀new[]与delete不匹配
❌错误示例:
Dog* dogs = new Dog[3];
delete dogs; // 错误:应使用delete[]
后果:只调用第一个Dog的析构函数,后两个对象的资源泄漏,且内存释放可能异常
4. 🥀重复释放或释放非动态内存
- 对同一指针多次
free/delete会导致堆损坏。 - 释放栈内存(如
int a; free(&a);)会导致程序崩溃。
六、❤️使用场景建议
- C 语言:只能使用
malloc/free(或calloc/realloc)。 - C++ 语言:
- 优先使用
new/delete(而非malloc/free),尤其是管理类对象时(需要构造 / 析构)。 - 更推荐使用智能指针(
std::unique_ptr/std::shared_ptr)和标准库容器(std::vector),避免手动调用new/delete。 - 需兼容 C 代码时,可混用
malloc与free,但注意不要与new/delete交叉使用。
- 优先使用
七、❤️总结
malloc/free是 C 语言的底层内存管理工具,仅负责内存的分配与释放,不涉及对象生命周期。new/delete是 C++ 的高级工具,不仅管理内存,还自动调用构造 / 析构函数,是面向对象编程的核心机制。- 两者不可混用,否则会导致内存泄漏、程序崩溃等未定义行为。现代 C++ 开发中,应尽量避免直接使用
new/delete,转而依赖智能指针等自动管理机制。
更多推荐



所有评论(0)