首页 > 解决方案 > 由函数指针初始化的 std::function 的异常安全

问题描述

的构造函数std::function未声明noexcept

template< class F > function( F f );

另一方面,C++ 参考提到以下内容:

如果 f 是函数指针或 std::reference_wrapper 则不抛出,否则可能抛出 std::bad_alloc 或存储的可调用对象的复制构造函数抛出的任何异常。

这是否意味着可以安全地声明以下类的构造函数,因为我使用指向静态成员函数的指针进行了noexcept初始化?std::function

class Worker
{
public:    
    Worker() noexcept {} // ok?
    void test() { reporter("test"); }
private:
    static void dummy(const std::string& ) {};
    std::function<void (const std::string&)> reporter = &dummy; // doesn't throw an exception?
};

int main()
{
    Worker w;
    w.test();
}

如果std::functionmember 是从 lambda 构造的,那么声明构造函数noexcept会是错误的吗?

class Worker
{
public:    
    Worker() noexcept {} // bad?
    void test() { reporter("Test"); }
private:
    std::function<void (const std::string&)> reporter = [](const std::string& ){}; // may throw?
};

我还注意到,当声明的构造函数noexcept默认时,GCC 会出错,因为它的异常规范与隐式异常规范不匹配,这是noexcept(false)由于std::function构造函数没有被声明为 noexcept。

class Worker
{
public:
    Worker() noexcept = default; // this won't compile    
    void test() { reporter("test"); }
private:
    static void dummy(const std::string& ) {};
    std::function<void (const std::string&)> reporter = &dummy;
};

标签: c++c++17

解决方案


这是否意味着可以安全地声明以下类的构造函数,因为我使用指向静态成员函数的指针进行了noexcept初始化?std::function

请注意,声明一个函数总是“安全的” noexcept。如果抛出异常,程序将终止,但这不是未定义的行为。

但是,是的,在您的情况下,不应抛出异常,因此不应发生程序终止。标准说:“抛出:Nothing if fis ...一个函数指针......”

如果std::functionmember 是从 lambda 构造的,那么声明构造函数noexcept会是错误的吗?

是的,在你想要的意义上它是“错误的”(如果程序抛出,程序将终止),因为 lambda 不是函数指针。相反,在 lambda 前面加上一元operator+,使其成为函数指针:

std::function<void (const std::string&)> reporter = +[](const std::string& ){};

我可能会在评论中提到这一点,特别是如果你没有评论为什么构造函数是noexcept.

我还注意到,当声明的构造函数noexcept默认时,GCC 会出错

GCC 和 Clang 的最新版本都没有给出错误,所以如果这是真的,那可能是根据标准发布的缺陷报告。


推荐阅读