【发布时间】:2021-02-21 13:30:30
【问题描述】:
我有一个类的析构函数是noexcept(false)。我知道它只在某些情况下抛出,我想将它用作具有noexcept 析构函数的类的成员变量。从https://en.cppreference.com/w/cpp/language/function-try-block 我读到“从函数体中的任何语句,或(对于构造函数)从任何成员或基构造函数,或(对于析构函数)从任何成员或基析构函数抛出的每个异常,都将控制转移到处理程序序列与常规 try 块中抛出的异常相同。”这让我觉得这应该是正确的:
#include <exception>
class ConditionallyThrowingDtor {
public:
bool willThrow = true;
ConditionallyThrowingDtor() = default;
~ConditionallyThrowingDtor() noexcept(false) {
if (willThrow) {
throw std::exception();
}
}
};
class NonThrowingDtor {
public:
ConditionallyThrowingDtor x;
~NonThrowingDtor() noexcept try {
x.willThrow = false;
} catch (...) {
// Ignore because we know it will never happen.
}
};
int main() {
// ConditionallyThrowingDtor y; // Throws on destruction as expected.
NonThrowingDtor x;
}
https://godbolt.org/z/ez17fx (MSVC)
我对@987654328@ 和~NonThrowingDtor() 上的函数try-block 的理解是noexcept 保证它不会抛出(并且它通过基本上执行try { ... } catch (...) { std::terminate(); } https://en.cppreference.com/w/cpp/language/noexcept_spec 来做到这一点。但是函数-try-block with catch (...) 并且没有额外的抛出应该保证它永远不会抛出。Clang 可以接受这个,但是正如 godbolt 链接所示,MSVC 说
<source>(23): warning C4297: 'NonThrowingDtor::~NonThrowingDtor': function assumed not to throw an exception but does
<source>(23): note: destructor or deallocator has a (possibly implicit) non-throwing exception specification
【问题讨论】:
-
为什么
catch块必须重新抛出?你是说noexcept表示try { ... } catch (...) { std::terminate(); },noexcept try { ... } catch (...) {}表示try { try { ... } catch (...) { std::terminate(); } } catch (...) {}? -
我的印象是不可能在不隐式抛出的情况下离开析构函数的
catch块,但显然你可以return明确地不重新抛出。 -
@Jarod42 析构函数类似于构造函数,因为它们在执行到达
catch的末尾时throw;。不同之处在于析构函数允许您使用return;来逃避该行为,而构造函数则不允许。我以为它们是相同的,但事实并非如此。 -
所以警告是合法的......奇怪的是,使用
return;并没有使警告静音。 -
@Ben "为什么 catch 块必须重新抛出?" — 因为标准是这样说的:eel.is/c++draft/except.handle#14.sentence-1。
标签: c++ noexcept function-try-block