什么是 new
运算符
new
运算符在 C++ 中用于动态分配内存,并返回指向新分配内存的指针。它通常用于在堆上分配对象或数组。new
运算符的返回值是一个指向该内存块的指针。
new
运算符的工作流程
- 内存分配:
new
运算符首先计算需要分配的内存大小,然后调用内存分配函数(如operator new
或低级别的malloc
)来在堆上分配内存空间。 - 对象构造:分配完内存后,
new
运算符会调用对象的构造函数(如果是类对象),初始化这块内存。 - 返回指针:
new
运算符最后返回一个指向这块新分配和初始化的内存的指针。
内存分配失败
如果 new
运算符失败(例如,系统内存不足),它会抛出一个 std::bad_alloc
异常。
new
和 delete
每一个使用 new
分配的内存块都应该使用 delete
释放,以避免内存泄漏。delete
运算符会首先调用析构函数(如果是对象),然后释放内存。
示例:使用 new
分配和释放内存
分配单个对象
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "Constructor called" << std::endl;
}
~MyClass() {
std::cout << "Destructor called" << std::endl;
}
};
int main() {
// 使用 new 分配单个对象
MyClass* obj = new MyClass;
// 使用对象
// ...
// 使用 delete 释放对象
delete obj;
return 0;
}
分配数组
#include <iostream>
int main() {
// 使用 new 分配数组
int* arr = new int[5];
// 初始化数组元素
for (int i = 0; i < 5; ++i) {
arr[i] = i * 2;
}
// 输出数组元素
for (int i = 0; i < 5; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
// 使用 delete[] 释放数组
delete[] arr;
return 0;
}
注意事项
- 内存泄漏:每次使用
new
分配的内存必须匹配一个delete
来释放。如果没能释放分配的内存,会导致内存泄漏。 - 异常安全:使用
new
分配内存时,应考虑异常安全性。如果在构造函数中抛出异常,应确保已分配的内存被合适地释放。 - 与 STL 容器结合:现代 C++ 推荐使用 STL 容器(如
std::vector
,std::string
)管理动态内存,这样可以避免手动内存管理带来的问题。 - 原始指针与智能指针:为避免手动管理内存造成的内存泄漏和悬空指针,现代 C++ 更多地使用智能指针(如
std::unique_ptr
,std::shared_ptr
)来自动管理内存生命周期。
高级用法:自定义 new
和 delete
你可以重载 new
和 delete
运算符以实现自定义内存管理机制。例如,记录分配和释放的调试信息,或从特殊的内存池中分配内存。
自定义 new
运算符
#include <iostream>
#include <cstdlib>
void* operator new(std::size_t size) {
std::cout << "Custom new for size: " << size << std::endl;
void* p = std::malloc(size);
if (!p) throw std::bad_alloc();
return p;
}
void operator delete(void* p) noexcept {
std::cout << "Custom delete" << std::endl;
std::free(p);
}
int main() {
int* p = new int; // 将调用自定义的 operator new
delete p; // 将调用自定义的 operator delete
return 0;
}
通过以上说明和例子,希望你对 C++ 中 new
运算符的工作原理、使用方法及应注意事项有了全面的了解。