答案是使用智能指针如std::unique_ptr和std::make_unique可确保异常安全。核心在于RAII原则,当new分配内存后构造函数抛出异常时,传统裸指针会导致内存泄漏,而std::make_unique在创建对象时将内存分配与资源管理绑定,若构造失败,其内部机制会自动释放已分配内存,避免泄漏。相比之下,try-catch仅能捕获bad_alloc,无法覆盖构造异常;std::nothrow不抛异常但返回nullptr,仍需手动管理资源且不解决构造异常问题。因此,推荐统一采用std::make_unique或std::make_shared,确保任何异常情况下资源都能正确释放,实现强异常安全保证。

C++中
new
要真正做到
new
try-catch
std::bad_alloc
delete
最直接、最推荐的解决方案是全面拥抱智能指针。
std::unique_ptr
std::shared_ptr
std::make_unique
std::make_shared
例如,考虑这样的场景:
立即学习“C++免费学习笔记(深入)”;
// 传统但有风险的写法 MyClass* obj = new MyClass(arg1, arg2); // 如果MyClass构造函数抛异常,这里就泄露了 // ... 使用obj ... delete obj; // 如果上面代码在delete前抛异常,这里也泄露了
而使用智能指针则完全不同:
// 推荐的异常安全写法 std::unique_ptr<MyClass> obj = std::make_unique<MyClass>(arg1, arg2); // 或者 std::shared_ptr<MyClass> obj = std::make_shared<MyClass>(arg1, arg2); // ... 使用obj ... // 无需手动delete,obj超出作用域时会自动释放
std::make_unique
std::make_shared
new
MyClass
make_unique
make_shared
另一个值得一提的是
std::nothrow
new
std::bad_alloc
nullptr
MyClass* obj = new (std::nothrow) MyClass();
if (obj == nullptr) {
// 处理内存分配失败的情况,例如记录日志、返回错误码等
// 注意:这里仅处理了分配失败,构造函数异常仍会抛出
} else {
// ... 使用obj ...
delete obj;
}但请注意,
std::nothrow
MyClass
std::nothrow
std::nothrow
总的来说,智能指针是实现
new
当
new
std::bad_alloc
处理
std::bad_alloc
try-catch
try {
// 尝试分配一个非常大的数组,模拟内存不足
int* largeArray = new int[1024 * 1024 * 1024]; // 假设这需要4GB内存
// ... 使用largeArray ...
delete[] largeArray;
} catch (const std::bad_alloc& e) {
std::cerr << "内存分配失败: " << e.what() << std::endl;
// 这里可以进行错误日志记录、通知用户、尝试释放一些缓存、
// 或者优雅地关闭程序。
// 例如,如果在一个服务器应用中,可能需要返回一个错误响应,
// 或者尝试重启某个子模块。
}这种方式的优点是清晰明了,能精确地知道是内存分配出了问题。但缺点是,它只能处理
new
new
try-catch
因此,更“优雅”的处理方式往往不是在每个
new
此外,我们还可以通过
std::set_new_handler
new
new
std::bad_alloc
std::set_new_handler
new
std::bad_alloc
std::abort()
#include <new>
#include <iostream>
#include <vector>
// 简单的内存清理函数
void myNewHandler() {
std::cerr << "New handler invoked! Attempting to free some memory..." << std::endl;
// 假设我们有一个全局的缓存,这里尝试清理它
static std::vector<char> largeCache(1024 * 1024 * 100); // 100MB
largeCache.clear(); // 释放一些内存
largeCache.shrink_to_fit();
std::cerr << "Cache cleared. Retrying allocation." << std::endl;
// 如果这里不抛异常,new会再次尝试分配
// 如果仍然失败,new handler会再次被调用
// 如果想立即终止,可以 throw std::bad_alloc() 或 std::abort()
}
int main() {
std::set_new_handler(myNewHandler);
try {
// 尝试分配一个非常大的数组
int* reallyLargeArray = new int[1024 * 1024 * 1024 * 4]; // 4GB
std::cout << "Successfully allocated really large array." << std::endl;
delete[] reallyLargeArray;
} catch (const std::bad_alloc& e) {
std::cerr << "Main catch block: " << e.what() << std::endl;
}
return 0;
}这种
new handler
总结来说,对于
std::bad_alloc
try-catch
std::nothrow
std::set_new_handler
这确实是一个核心痛点,也是为什么C++异常安全编程如此重要的原因之一。当
new
避免这种情况的黄金法则,如前所述,就是使用智能指针的工厂函数 std::make_unique
std::make_shared
我们来深入分析一下为什么它们能解决问题。 当你写
MyClass* obj = new MyClass();
operator new
MyClass
如果第二步抛出异常
以上就是C++new操作符异常安全使用方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号