C++中类A的~A(){}与~A() throw(){}的区别及throw()在析构函数中的用途
Alright, let's break down the key differences between the two destructor declarations you've mentioned, and explain why the throw() specifier exists for destructors in C++.
Core Differences Between ~A() {} and ~A() throw() {}
1. Exception Throwing Constraints
~A() {}(no exception specification)- In C++98: This destructor has no restrictions—it’s allowed to throw any type of exception, and if an exception escapes the destructor, it will propagate normally (unless it happens during stack unwinding, which we’ll cover next).
- In C11 and later: Destructors are implicitly
noexcept(true)by default. That means they’re treated as if they promise not to throw exceptions, unless you explicitly mark them withnoexcept(false)or an old-style spec likethrow(...). So in modern C, the bare destructor behaves almost likethrow()—but with better compiler support and clarity.
~A() throw() {}(empty exception specification)- This is an old C++98-style spec that explicitly guarantees the destructor will never throw any exceptions. If any exception is thrown from inside this destructor (or from a function it calls that isn’t caught), the runtime will immediately call
std::terminate()to abort the program—no exception propagation happens here.
- This is an old C++98-style spec that explicitly guarantees the destructor will never throw any exceptions. If any exception is thrown from inside this destructor (or from a function it calls that isn’t caught), the runtime will immediately call
2. Behavior During Stack Unwinding
Stack unwinding is the process where the runtime destroys local objects when an exception is being handled. Here’s where the difference becomes critical:
- For a bare
~A() {}(C++98): If an exception is already in flight during stack unwinding, and this destructor throws another uncaught exception, the program will callstd::terminate()anyway—you can’t have two active unhandled exceptions. - For
~A() throw() {}: Any uncaught exception originating from this destructor, regardless of context, triggersstd::terminate()immediately. This is stricter than the bare destructor in C++98, as it enforces the "no exceptions" promise at all times.
What’s the Purpose of throw() in a Destructor?
The throw() specifier serves three main purposes:
- Clear Contract with Developers & Compilers: It explicitly documents that this destructor is safe to call in any context, including during exception handling. Other programmers reading your code will immediately know they don’t have to worry about exceptions escaping this destructor. Compilers can also use this information to optimize code (though modern compilers are good at inferring this even without the spec).
- Prevent Silent Runtime Disasters: Since destructors are often called automatically during stack unwinding, allowing exceptions to escape them can lead to immediate program termination anyway. Using
throw()makes this behavior explicit—if an exception does slip through, the program terminates immediately instead of potentially entering an undefined state. - Legacy Compatibility: Before C11 introduced
noexcept,throw()was the standard way to mark a function as non-throwing. Whilenoexceptis now the recommended approach (it’s more flexible and readable),throw()still works in modern C (though it’s deprecated in favor ofnoexcept(true)).
内容的提问来源于stack exchange,提问作者rajesh
相关产品推荐
相关产品推荐

