【问题标题】:When should one explicitly attribute noexcept?什么时候应该明确属性 noexcept?
【发布时间】:2020-12-22 22:44:40
【问题描述】:
什么时候应该将noexcept 属性添加到函数中?即编译器什么时候不能告诉函数抛出?是否应该对所有内容进行标记,还是有办法分辨?
我不喜欢过早优化,也不喜欢过早归因。我不知道有什么方法可以像优化时分析性能一样“分析”noexcept 的需求。
在评估需要的地方时,请评论最常见的编译器,例如MSVC、GCC 等
【问题讨论】:
标签:
c++
gcc
visual-c++
clang
【解决方案1】:
C++ Core Guidelines 建议基本上在代码不会抛出的任何地方使用它。这对于库来说非常重要,因为代码检查器会使用您调用的函数来查看它是否为 noexcept,否则您会收到一连串的警告。
也就是说,最重要的建议是使用swap、move 和析构函数noexcept。
C++ 核心指南还建议创建默认构造函数noexcept,这通常很好,但许多模式(如pImpl idiom)通常在其默认构造函数中分配内存。因此,我通常在默认构造函数(或只接受默认参数的构造函数)上使用noexcept,但如果我知道它可以抛出,我会明确标记它nothrow(false)。
如果您将默认构造函数、复制构造函数、赋值运算符、移动构造函数、移动运算符或析构函数声明为 =default,则默认为 noexcept。所有的析构函数也是隐式的noexcept。
有一个概念,您可以标记 noexcept 来表示“如果这确实抛出,请继续并崩溃”。我发现这个概念有点模糊,所以在我的代码中我标记了 可以 抛出 noexcept(false) 或不指定它的东西。这通常是调用new 或初始化std 容器的东西。
【解决方案2】:
什么时候应该将noexcept 属性添加到函数中?
当您想要记录并强制执行函数永远不会抛出时。
重要的是要记住,这里的错误意味着将调用std::terminate() 而不是传播异常。因此,这可能是一种悲观。
即编译器什么时候无法判断函数抛出?
恰恰相反:编译器必须假设一切都抛出,除非它可以证明不是这样(或被告知不是这样)。
当它具有所需的定义时,它将能够证明它。例如,在没有 LTO 的 TU 之间,它不会。
我不知道如何“描述”noexcept 的需求
就像在任何其他情况下一样:您测量有无。
对于大多数项目,致力于启用 LTO 是一种更好的处理方式。