【问题标题】:Should function-try-block of d'tor allow handling of throwing member-variable d'tor?d'tor 的 function-try-block 是否应该允许处理抛出的成员变量 d'tor?
【发布时间】: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)

我对@9​​87654328@ 和~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


【解决方案1】:
~NonThrowingDtor() noexcept try {
        x.willThrow = false;
    } catch (...) { 
        // Ignore because we know it will never happen.
    }

“错误”等同于

~NonThrowingDtor() noexcept try {
        x.willThrow = false;
    } catch (...) {
        throw;
    }

就这么简单

~NonThrowingDtor() noexcept
{
    x.willThrow = false;
}

要不传播异常,您必须明确使用return

~NonThrowingDtor() noexcept try {
        x.willThrow = false;
    } catch (...) { 
        return; // Required to not propagate exception.
    }

不幸的是,msvc 仍然会用这种不会抛出的表单发出警告。
(另一方面,在这种情况下,clang/gcc 不会对 implicit 发出警告(但会发出显式警告)throw

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 2016-11-28
    • 2020-11-24
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多