new操作符基本用法
- 分配单个对象:
- 语法:
type* pointer = new type;
- 例如:
int* num = new int;
这行代码在堆上分配了一个 int
类型的空间,并返回指向该空间的指针,赋值给 num
。
- 也可以在分配时初始化:
int* num = new int(5);
这里初始化 int
为 5
。
- 分配数组:
- 语法:
type* pointer = new type[size];
- 例如:
int* arr = new int[10];
在堆上分配了一个包含 10
个 int
类型元素的数组,并返回指向数组首元素的指针,赋值给 arr
。
delete操作符基本用法
- 释放单个对象:
- 语法:
delete pointer;
- 例如:
int* num = new int; delete num;
释放之前用 new
分配的 int
类型对象。
- 释放数组:
- 语法:
delete[] pointer;
- 例如:
int* arr = new int[10]; delete[] arr;
释放之前用 new
分配的数组。
可能导致内存泄漏的场景
- 忘记调用delete:
void leak1() {
int* num = new int;
// 没有调用delete num;
}
- 在函数
leak1
中,分配了一个 int
类型的对象,但没有释放,函数结束时,这块内存无法再被访问,导致内存泄漏。
- 异常处理不当:
void leak2() {
int* arr = new int[10];
try {
// 可能抛出异常的代码
throw std::exception();
} catch(...) {
// 没有释放arr
}
}
- 在
leak2
函数中,分配了数组 arr
,如果在 try
块中抛出异常,并且 catch
块没有释放 arr
,就会导致内存泄漏。
- 指针赋值丢失:
void leak3() {
int* num1 = new int;
int* num2 = num1;
num1 = nullptr;
// 此时num1指向nullptr,而num2也没有delete,导致内存泄漏
}
- 这里最初
num1
指向新分配的内存,num2
也指向相同内存,然后 num1
被赋值为 nullptr
,而 num2
没有释放内存,造成内存泄漏。
避免内存泄漏的方法
- 智能指针:
#include <memory>
void noLeak1() {
std::unique_ptr<int> num(new int);
// 函数结束时,std::unique_ptr自动调用delete释放内存
}
#include <memory>
void noLeak2() {
std::shared_ptr<int> num(new int);
// 当引用计数为0时,自动释放内存
std::shared_ptr<int> num2 = num;
}
- RAII(Resource Acquisition Is Initialization):
- 自定义类来管理资源,在构造函数中分配资源,在析构函数中释放资源。
class Resource {
public:
Resource() : data(new int) {}
~Resource() { delete data; }
private:
int* data;
};
void noLeak3() {
Resource res;
// 函数结束时,res的析构函数会释放分配的内存
}
- 异常安全处理:
- 使用智能指针或RAII类在异常发生时能自动释放资源。如果手动管理内存,在
catch
块中正确释放资源。
void noLeak4() {
int* arr = nullptr;
try {
arr = new int[10];
// 可能抛出异常的代码
throw std::exception();
} catch(...) {
if(arr) {
delete[] arr;
}
throw;
}
}