C++析构函数中抛出异常问题详解与解决方案
一、问题概述
析构函数中抛出异常是C++编程中极其危险的行为,主要问题包括:
- 程序终止:如果在栈展开过程中析构函数抛出异常,程序会调用
std::terminate() - 资源泄漏:异常中断资源释放过程
- 未定义行为:破坏异常处理机制
- 调试困难:异常信息丢失,难以追踪根本原因
二、C++标准规定
2.1 标准规则
根据C++标准(§15.2/3):
- 如果异常正在传播时,从析构函数抛出第二个异常,程序将终止
- 析构函数默认标记为
noexcept(true)(C++11起)
class Resource {
public:
~Resource() {
// C++11起:隐式声明为 noexcept
// 如果这里抛出异常,程序可能终止
}
};
三、问题场景分析
3.1 栈展开过程中的异常
// ❌ 危险示例:析构函数在栈展开中抛出异常
#include <iostream>
#include <stdexcept>
class DangerousResource {
public:
DangerousResource(const char* name) : name_(name) {
std::cout << "Acquiring: " << name_ << std::endl;
}
~DangerousResource() {
std::cout << "Releasing: " << name_ << std::endl;
// 危险:可能在栈展开时抛出异常
if (std::uncaught_exceptions() > 0) {
std::cout << "WARNING: Exception already active!" << std::endl;
}
throw std::runtime_error("Error in ~DangerousResource()");
}
private:
const char* name_;
};
void risky_function() {
DangerousResource res1("Resource1");
DangerousResource res2("Resource2");
throw std::runtime_error("Primary exception");
}
int main() {
try {
risky_function();
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
// 实际上程序可能在析构函数中终止
}
return 0;
}
// 输出可能:
// Acquiring: Resource1
// Acquiring: Resource2
// Releasing: Resource2
// terminate called after throwing an instance of 'std::runtime_error'
// 程序终止!
3.2 容器元素析构异常
// ❌ 危险示例:容器中的对象析构抛出异常
#include <vector>
#include <iostream>
#include <memory>
class Element {
public:
Element(int id) : id_(id) {
std::cout << "Element " << id_ << " created" << std::endl;
}
~Element() noexcept(false) { // 错误地关闭noexcept
std::cout << "Element " << id_ << " destroying" << std::endl;
if (id_ == 2) {
throw std::runtime_error("Failed to destroy element 2");
}
}
private:
int id_;
};
int main() {
try {
std::vector<Element> elements;
elements.reserve(5);
for (int i = 0; i < 5; ++i) {
elements.emplace_back(i);
}
// vector析构时会逐个销毁元素
// 当元素2抛出异常时,其他元素可能不会被正确销毁
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
}
return 0;
}
// 问题:元素3、4、5可能泄漏资源
3.3 继承体系中的析构函数
// ❌ 危险示例:基类和派生类析构函数都可能抛出异常
#include <iostream>
#include <memory>
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
cleanup_base();
}
virtual void cleanup_base() {
// 可能抛出异常
throw std::runtime_error("Base cleanup failed");
}
};
class Derived : public Base {
public:
~Derived() override {
std::cout << "Derived destructor" << std::endl;
cleanup_derived();
}
void cleanup_derived() {
// 也可能抛出异常
throw std::runtime_error("Derived cleanup failed");
}
void cleanup_base() override {
// 重写基类清理
std::cout << "Derived cleaning up base resources" << std::endl;
// 仍然可能抛出异常
}
};
int main() {
try {
Derived d;
// d离开作用域时,会先调用~Derived(),再调用~Base()
// 如果两者都抛出异常,程序终止
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
}
return 0;
}
四、解决方案
4.1 基本原则:不在析构函数中抛出异常
4.1.1 使用noexcept确保安全
// ✅ 正确示例:使用noexcept确保析构函数安全
#include <iostream>
#include <fstream>
class SafeFile {
private:
std::FILE* file_;
public:
explicit SafeFile(const char* filename)
: file_(std::fopen(filename, "r")) {
if (!file_) {
throw std::runtime_error("Failed to open file");
}
std::cout << "File opened: " << filename << std::endl;
}
// 声明为noexcept,承诺不抛出异常
~SafeFile() noexcept {
std::cout << "Closing file" << std::endl;
if (file_) {
// 即使失败也不抛出异常
std::fclose(file_);
// 可以记录日志,但不抛出
}
}
// 禁止拷贝
SafeFile(const SafeFile&) = delete;
SafeFile& operator=(const SafeFile&) = delete;
// 允许移动
SafeFile(SafeFile&& other) noexcept
: file_(other.file_) {
other.file_ = nullptr;
}
SafeFile& operator=(SafeFile&& other) noexcept {
if (this != &other) {
cleanup();
file_ = other.file_;
other.file_ = nullptr;
}
return *this;
}
void read_data() {
// 使用文件...
}
private:
void cleanup() noexcept {
if (file_) {
std::fclose(file_);
file_ = nullptr;
}
}
};
int main() {
try {
SafeFile file("data.txt");
file.read_data();
// 析构函数被调用,保证不抛出异常
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
4.1.2 提供显式释放函数
// ✅ 正确示例:提供显式释放函数,析构函数作为后备
#include <iostream>
#include <memory>
#include <mutex>
class ThreadSafeResource {
private:
std::unique_ptr<int[]> data_;
std::mutex mutex_;
bool released_;
public:
ThreadSafeResource(size_t size)
: data_(std::make_unique<int[]>(size)),
released_(false) {
std::cout << "Resource allocated" << std::endl;
}
// 显式释放函数,可以抛出异常
void release() {
std::lock_guard<std::mutex> lock(mutex_);
if (released_) {
return; // 已经释放
}
std::cout << "Releasing resource..." << std::endl;
// 可能抛出异常的清理操作
perform_complex_cleanup();
data_.reset();
released_ = true;
std::cout << "Resource released successfully" << std::endl;
}
// 析构函数作为后备,不抛出异常
~ThreadSafeResource() noexcept {
try {
if (!released_) {
std::cout << "Warning: Resource not explicitly released, "
<< "performing emergency cleanup" << std::endl;
std::lock_guard<std::mutex> lock(mutex_);
if (!released_) {
// 执行简单的、不会抛出异常的清理
data_.reset();
released_ = true;
}
}
} catch (...) {
// 捕获所有异常,防止传播
std::cerr << "ERROR: Unexpected exception in destructor" << std::endl;
// 记录日志,但不重新抛出
}
}
// 使用资源
void process() {
std::lock_guard<std::mutex> lock(mutex_);
if (released_) {
throw std::runtime_error("Resource already released");
}
// 处理数据...
}
private:
void perform_complex_cleanup() {
// 复杂的清理逻辑,可能失败
// 但可以抛出异常,因为不是在析构函数中
if (data_) {
// 模拟可能失败的操作
bool cleanup_failed = false; // 模拟变量
if (cleanup_failed) {
throw std::runtime_error("Complex cleanup failed");
}
}
}
};
int main() {
try {
ThreadSafeResource resource(1024);
resource.process();
// 显式释放,可以处理异常
resource.release();
} catch (const std::exception& e) {
std::cerr << "Error during operation: " << e.what() << std::endl;
// 即使release()抛出异常,析构函数仍会安全清理
}
return 0;
}
4.2 异常安全的资源管理
4.2.1 RAII模式与异常安全
// ✅ 正确示例:异常安全的RAII包装器
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
// 通用RAII包装器
template<typename Resource, typename Cleanup>
class ScopedResource {
private:
Resource resource_;
Cleanup cleanup_;
bool released_;
public:
// 构造函数可能抛出异常
template<typename... Args>
ScopedResource(Cleanup cleanup, Args&&... args)
: resource_(std::forward<Args>(args)...),
cleanup_(std::move(cleanup)),
released_(false) {
}
// 移动构造
ScopedResource(ScopedResource&& other) noexcept
: resource_(std::move(other.resource_)),
cleanup_(std::move(other.cleanup_)),
released_(other.released_) {
other.released_ = true;
}
// 析构函数不抛出异常
~ScopedResource() noexcept {
if (!released_) {
try {
cleanup_(resource_);
} catch (...) {
// 记录错误但不抛出
std::cerr << "WARNING: Cleanup threw exception, ignoring" << std::endl;
}
}
}
// 显式释放
void release() {
if (!released_) {
cleanup_(resource_);
released_ = true;
}
}
// 获取资源
Resource& get() { return resource_; }
const Resource& get() const { return resource_; }
// 禁止拷贝
ScopedResource(const ScopedResource&) = delete;
ScopedResource& operator=(const ScopedResource&) = delete;
};
// 使用示例
void demo_scoped_resource() {
// 示例1:文件句柄
auto file_cleanup = [](FILE* f) {
if (f && f != stdin && f != stdout && f != stderr) {
std::cout << "Closing file" << std::endl;
if (std::fclose(f) != 0) {
// 记录错误但不抛出
std::cerr << "Failed to close file" << std::endl;
}
}
};
{
ScopedResource<FILE*, decltype(file_cleanup)>
file(file_cleanup, std::fopen("test.txt", "w"));
if (file.get()) {
std::fprintf(file.get(), "Hello World\n");
}
// 文件自动关闭,即使抛出异常
}
// 示例2:内存分配
auto memory_cleanup = [](int* ptr) {
std::cout << "Freeing memory" << std::endl;
delete[] ptr;
};
ScopedResource<int*, decltype(memory_cleanup)>
memory(memory_cleanup, new int[100]);
// 使用内存...
memory.get()[0] = 42;
}
4.2.2 使用std::unique_ptr自定义删除器
// ✅ 正确示例:使用unique_ptr自定义删除器
#include <iostream>
#include <memory>
#include <vector>
// 自定义删除器,保证不抛出异常
struct SafeFileDeleter {
void operator()(FILE* f) const noexcept {
if (f && f != stdin && f != stdout && f != stderr) {
std::cout << "Deleter closing file" << std::endl;
// 忽略错误,保证不抛出
std::fclose(f);
}
}
};
using SafeFilePtr = std::unique_ptr<FILE, SafeFileDeleter>;
// 复杂资源的自定义删除器
class DatabaseConnection {
public:
static DatabaseConnection* connect(const std::string& url) {
std::cout << "Connecting to database: " << url << std::endl;
return new DatabaseConnection();
}
void disconnect() {
std::cout << "Disconnecting database" << std::endl;
// 可能抛出异常的操作
throw std::runtime_error("Disconnection failed");
}
void query(const std::string& sql) {
std::cout << "Executing: " << sql << std::endl;
}
};
struct SafeDatabaseDeleter {
void operator()(DatabaseConnection* db) const noexcept {
if (db) {
try {
db->disconnect(); // 可能抛出异常
} catch (const std::exception& e) {
// 记录但不传播异常
std::cerr << "Database disconnection error: "
<< e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown database disconnection error" << std::endl;
}
delete db;
}
}
};
using SafeDatabasePtr = std::unique_ptr<DatabaseConnection, SafeDatabaseDeleter>;
int main() {
// 文件示例
SafeFilePtr file(std::fopen("data.txt", "w"));
if (file) {
std::fprintf(file.get(), "Test data\n");
}
// 数据库示例
try {
SafeDatabasePtr db(DatabaseConnection::connect("localhost/test"));
db->query("SELECT * FROM users");
// 即使后面抛出异常,删除器也会安全清理
throw std::runtime_error("Simulated error");
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
// db的删除器会被调用,不会导致程序终止
}
return 0;
}
4.3 处理多重资源清理
4.3.1 资源收集器模式
// ✅ 正确示例:资源收集器模式
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
class ResourceCollector {
private:
std::vector<std::function<void()>> cleanup_actions_;
bool committed_;
public:
ResourceCollector() : committed_(false) {}
~ResourceCollector() noexcept {
rollback();
}
// 添加清理动作
template<typename Fn>
void add_cleanup(Fn&& cleanup) {
cleanup_actions_.emplace_back(std::forward<Fn>(cleanup));
}
// 提交所有资源(不执行清理)
void commit() noexcept {
committed_ = true;
cleanup_actions_.clear();
}
// 回滚(执行所有清理)
void rollback() noexcept {
if (committed_) {
return;
}
// 逆序执行清理(LIFO)
for (auto it = cleanup_actions_.rbegin();
it != cleanup_actions_.rend(); ++it) {
try {
(*it)();
} catch (const std::exception& e) {
std::cerr << "Cleanup error (ignored): " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown cleanup error (ignored)" << std::endl;
}
}
cleanup_actions_.clear();
committed_ = true;
}
};
// 使用示例
class TransactionalFile {
private:
FILE* file_;
ResourceCollector& collector_;
public:
TransactionalFile(const char* filename,
ResourceCollector& collector)
: collector_(collector) {
file_ = std::fopen(filename, "w");
if (!file_) {
throw std::runtime_error("Failed to open file");
}
// 注册清理动作
collector_.add_cleanup([this]() {
if (file_) {
std::cout << "Rollback: closing file" << std::endl;
std::fclose(file_);
file_ = nullptr;
}
});
}
~TransactionalFile() {
// 析构函数不做清理,由ResourceCollector管理
}
void write(const char* data) {
if (!file_) {
throw std::runtime_error("File not open");
}
std::fprintf(file_, "%s", data);
}
};
void perform_transaction() {
ResourceCollector collector;
try {
TransactionalFile file1("file1.txt", collector);
TransactionalFile file2("file2.txt", collector);
file1.write("Data for file1\n");
file2.write("Data for file2\n");
// 模拟错误
throw std::runtime_error("Transaction failed");
// 如果成功到达这里
collector.commit();
std::cout << "Transaction committed" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Transaction error: " << e.what() << std::endl;
// collector的析构函数会自动回滚
// 或者可以显式调用:collector.rollback();
}
// 离开作用域时,如果未提交,collector会回滚
}
int main() {
perform_transaction();
return 0;
}
4.4 处理继承体系中的析构函数
4.4.1 虚析构函数的异常安全
// ✅ 正确示例:安全的虚析构函数实现
#include <iostream>
#include <memory>
#include <mutex>
class Base {
public:
virtual ~Base() noexcept {
// 基类析构函数必须处理异常安全
try {
cleanup();
} catch (...) {
handle_destructor_exception();
}
}
// 显式释放函数
virtual void release() {
cleanup();
}
protected:
virtual void cleanup() {
// 基类清理逻辑
std::cout << "Base cleanup" << std::endl;
}
private:
void handle_destructor_exception() noexcept {
// 记录错误,保证不抛出
std::cerr << "CRITICAL: Exception in base destructor" << std::endl;
// 可能的紧急清理
}
};
class Derived : public Base {
protected:
void cleanup() override {
// 先清理派生类资源
cleanup_derived();
// 再调用基类清理
Base::cleanup();
}
private:
void cleanup_derived() {
std::cout << "Derived cleanup" << std::endl;
// 可能抛出异常的操作
bool should_throw = false; // 示例
if (should_throw) {
throw std::runtime_error("Derived cleanup failed");
}
}
};
class SafeDerived : public Base {
public:
// 更安全的做法:覆盖release而不是cleanup
void release() override {
try {
cleanup_safe();
Base::release();
} catch (const std::exception& e) {
std::cerr << "Error in SafeDerived::release: "
<< e.what() << std::endl;
throw; // 可以在release中抛出
}
}
private:
void cleanup_safe() {
std::cout << "SafeDerived cleanup" << std::endl;
// 清理逻辑
}
// 覆盖cleanup但要保证不抛出
void cleanup() noexcept override {
try {
cleanup_safe();
} catch (...) {
std::cerr << "Suppressed exception in SafeDerived::cleanup"
<< std::endl;
}
}
};
int main() {
try {
std::unique_ptr<Base> obj = std::make_unique<Derived>();
// 最好显式释放
obj->release();
} catch (const std::exception& e) {
std::cerr << "Caught: " << e.what() << std::endl;
}
// 即使不调用release,析构函数也是安全的
{
std::unique_ptr<Base> obj = std::make_unique<SafeDerived>();
// 离开作用域时,析构函数不会抛出异常
}
return 0;
}
五、高级技巧和最佳实践
5.1 使用std::uncaught_exceptions()检测异常状态
// ✅ 正确示例:使用C++17的std::uncaught_exceptions()
#include <iostream>
#include <exception>
class SmartResource {
public:
SmartResource() {
std::cout << "SmartResource created" << std::endl;
}
~SmartResource() {
int uncaught = std::uncaught_exceptions();
std::cout << "Destructor called with "
<< uncaught << " uncaught exceptions" << std::endl;
if (uncaught > 0) {
// 有异常正在传播,进行最小化安全清理
emergency_cleanup();
} else {
// 正常清理,可以进行复杂操作
normal_cleanup();
}
}
void use() {
std::cout << "Using resource" << std::endl;
}
private:
void emergency_cleanup() noexcept {
std::cout << "Performing emergency cleanup" << std::endl;
// 只做不会抛出异常的操作
}
void normal_cleanup() {
std::cout << "Performing normal cleanup" << std::endl;
try {
// 可能抛出异常的复杂清理
if (should_fail()) {
throw std::runtime_error("Normal cleanup failed");
}
} catch (const std::exception& e) {
std::cerr << "Cleanup failed: " << e.what() << std::endl;
// 记录但不重新抛出
}
}
bool should_fail() { return false; } // 示例
};
void test_exception_state() {
try {
SmartResource res;
res.use();
throw std::runtime_error("Test exception");
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
}
}
int main() {
test_exception_state();
return 0;
}
5.2 双重保险模式
// ✅ 正确示例:双重保险模式
#include <iostream>
#include <memory>
#include <mutex>
class DoubleSafetyResource {
private:
struct Impl;
std::unique_ptr<Impl> impl_;
public:
DoubleSafetyResource();
~DoubleSafetyResource() noexcept;
// 显式关闭,可能抛出异常
void close();
// 使用资源
void use();
private:
void safe_cleanup() noexcept;
};
struct DoubleSafetyResource::Impl {
FILE* file = nullptr;
bool closed = false;
std::mutex mutex;
~Impl() noexcept {
safe_close();
}
void safe_close() noexcept {
std::lock_guard<std::mutex> lock(mutex);
if (file && !closed) {
std::fclose(file);
file = nullptr;
closed = true;
}
}
void close_with_checks() {
std::lock_guard<std::mutex> lock(mutex);
if (closed) {
throw std::runtime_error("Already closed");
}
if (file) {
// 复杂的关闭逻辑
if (std::fclose(file) != 0) {
throw std::runtime_error("Failed to close file");
}
file = nullptr;
closed = true;
}
}
};
DoubleSafetyResource::DoubleSafetyResource()
: impl_(std::make_unique<Impl>()) {
impl_->file = std::fopen("data.bin", "wb");
if (!impl_->file) {
throw std::runtime_error("Failed to open file");
}
}
DoubleSafetyResource::~DoubleSafetyResource() noexcept {
safe_cleanup();
}
void DoubleSafetyResource::safe_cleanup() noexcept {
if (impl_) {
impl_->safe_close();
}
}
void DoubleSafetyResource::close() {
if (impl_) {
impl_->close_with_checks();
}
}
void DoubleSafetyResource::use() {
if (!impl_ || impl_->closed) {
throw std::runtime_error("Resource not available");
}
// 使用资源
}
int main() {
try {
DoubleSafetyResource resource;
resource.use();
// 首选:显式关闭,可以处理异常
resource.close();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
// 析构函数仍会安全清理
}
return 0;
}
5.3 单元测试策略
// ✅ 正确示例:测试析构函数的异常安全性
#include <iostream>
#include <cassert>
#include <stdexcept>
#include <csignal>
#include <cstdlib>
// 测试辅助工具
class DestructorTestHarness {
static bool terminate_called;
public:
static void setup() {
std::set_terminate([]() {
terminate_called = true;
std::cerr << "std::terminate called as expected" << std::endl;
std::exit(0); // 正常退出测试
});
}
static bool was_terminate_called() {
return terminate_called;
}
static void reset() {
terminate_called = false;
}
};
bool DestructorTestHarness::terminate_called = false;
// 被测试的类
class TestClass {
public:
enum class Mode {
Safe,
Throwing,
DoubleThrow
};
static int instance_count;
TestClass(Mode mode = Mode::Safe) : mode_(mode) {
++instance_count;
}
~TestClass() noexcept(false) {
--instance_count;
switch (mode_) {
case Mode::Safe:
// 安全,不抛出
break;
case Mode::Throwing:
throw std::runtime_error("TestClass destructor threw");
break;
case Mode::DoubleThrow:
if (std::uncaught_exceptions() > 0) {
// 已经有异常在传播,再抛出一个会导致terminate
throw std::logic_error("Second exception during stack unwind");
}
break;
}
}
private:
Mode mode_;
};
int TestClass::instance_count = 0;
// 测试用例
void test_safe_destructor() {
std::cout << "Testing safe destructor..." << std::endl;
DestructorTestHarness::reset();
{
TestClass obj(TestClass::Mode::Safe);
assert(TestClass::instance_count == 1);
}
assert(TestClass::instance_count == 0);
assert(!DestructorTestHarness::was_terminate_called());
std::cout << "PASS" << std::endl;
}
void test_throwing_destructor_no_exception() {
std::cout << "Testing throwing destructor (no active exception)..." << std::endl;
DestructorTestHarness::reset();
try {
TestClass obj(TestClass::Mode::Throwing);
// obj离开作用域,析构函数抛出异常
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
assert(TestClass::instance_count == 0);
assert(!DestructorTestHarness::was_terminate_called());
std::cout << "PASS" << std::endl;
return;
}
assert(false && "Should have caught exception");
}
void test_double_throwing_destructor() {
std::cout << "Testing double-throwing destructor..." << std::endl;
DestructorTestHarness::reset();
try {
TestClass inner(TestClass::Mode::DoubleThrow);
throw std::runtime_error("First exception");
} catch (...) {
// 内层对象在栈展开时析构,会抛出第二个异常
// 这应该导致terminate
}
// 如果到达这里,测试失败
assert(false && "Should have terminated");
}
int main() {
DestructorTestHarness::setup();
try {
test_safe_destructor();
test_throwing_destructor_no_exception();
// 这个测试会导致terminate,所以单独运行
// test_double_throwing_destructor();
std::cout << "\nAll tests passed!" << std::endl;
return 0;
} catch (const std::exception& e) {
std::cerr << "Test failed: " << e.what() << std::endl;
return 1;
}
}
六、总结和最佳实践
6.1 核心原则
- 绝不从析构函数中抛出异常
- 析构函数应声明为
noexcept - 使用RAII模式管理资源
- 提供显式释放函数处理可能失败的操作
6.2 设计模式
| 模式 | 适用场景 | 优点 |
|---|---|---|
| 显式释放函数 | 需要处理可能失败的清理操作 | 可以抛出异常,更好的错误处理 |
| 双重保险 | 关键资源,必须保证清理 | 即使显式释放失败,析构函数也能安全清理 |
| 资源收集器 | 事务性操作,需要原子性 | 支持提交/回滚语义 |
| 智能指针+自定义删除器 | 通用资源管理 | 自动生命周期管理 |
6.3 代码检查清单
// 析构函数设计检查清单
class YourClass {
public:
// ✅ 正确做法
~YourClass() noexcept { // 1. 添加noexcept
try {
cleanup(); // 2. 在try块中清理
} catch (...) {
// 3. 记录错误但不传播
log_error("Destructor cleanup failed");
// 4. 执行紧急清理(如果需要)
emergency_cleanup();
}
}
// ✅ 提供显式释放函数
void release() {
// 可以抛出异常
complex_cleanup();
released_ = true;
}
private:
void cleanup() noexcept { // 5. 清理函数也声明noexcept
if (!released_) {
simple_cleanup(); // 6. 只做简单、安全的操作
}
}
void complex_cleanup() {
// 复杂逻辑,可能失败
}
void simple_cleanup() noexcept {
// 简单逻辑,保证不失败
}
void emergency_cleanup() noexcept {
// 最后的安全网
}
bool released_ = false;
};
6.4 现代C++特性
// C++17/20最佳实践
class ModernResource {
public:
ModernResource() {
// 获取资源
}
~ModernResource() {
// 使用if constexpr或concepts进行条件清理
if constexpr (has_safe_cleanup_v<ResourceType>) {
resource_.cleanup_safe();
} else {
// 后备方案
}
}
// C++20概念约束的显式释放
template<typename T>
requires std::is_invocable_v<T, Resource&>
void release_with(T&& cleanup_fn) {
cleanup_fn(resource_);
released_ = true;
}
private:
Resource resource_;
bool released_ = false;
};
记住:析构函数中的异常就像是飞机降落时引擎失效——你无法安全地处理它,所以必须首先防止它发生。
C++析构函数异常处理解析
645

被折叠的 条评论
为什么被折叠?



