值得注意的是,在权力圈子里有一个关于 nothrow 相关问题的有趣讨论。我强烈推荐阅读这些:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3227.html
http://www.stroustrup.com/N3202-noexcept.pdf
显然,相当有影响力的人有兴趣在 C++ 中添加某种自动 nothrow 演绎。
经过一番思考后,我将位置更改为几乎相反,见下文
考虑一下:
即noexcept
既伤害你又让你受益。如果函数是内联的,情况就不是这样了!当它被内联时 - noexcept 对声明没有任何好处(声明和定义成为一件事)......除非你真的希望编译器为了安全起见强制执行它。安全我的意思是你宁愿终止而不是产生错误的结果。
现在应该很明显了——声明内联函数是没有意义noexcept
的(请记住,并非每个内联函数都会被内联)。
让我们看一下不抛出的不同类别的函数(你只知道它们不会抛出):
非内联,编译器可以证明它不会抛出 -noexcept
不会伤害函数体(编译器将简单地忽略规范)并且调用站点将从这个承诺中受益
非内联,编译器无法证明它不会抛出 -noexcept
会伤害函数体,但有利于调用站点(很难说什么更有益)
内联,编译器可以证明它不会抛出 -noexcept
没有用
内联,编译器无法证明它不会抛出 -noexcept
会伤害调用站点
如您所见,nothrow
这只是设计糟糕的语言功能。它仅在您想强制执行无异常承诺时才有效。没有办法正确使用它——它可以给你“安全”,但不能给你性能。
noexcept
关键字最终被用作承诺(声明时)和强制执行(定义时)——我认为这不是一个完美的方法(哈哈,第二次尝试异常规范,我们仍然没有做对)。
那么该怎么办?
声明你的行为(唉,语言在这里没有任何帮助)!例如:
void push_back(int k); // throws only if there is no unused memory
不要noexcept
使用内联函数(除非它不太可能被内联,例如非常大)
对于非内联函数(或不太可能被内联的函数)——进行调用。较大的函数得到较小noexcept
的负面影响(相对而言) - 在某些时候为调用者的利益指定它可能是有意义的
在noexcept
移动构造函数和移动赋值运算符(和析构函数?)上使用。它可能会对它们产生负面影响,但如果你不这样做 - 某些库函数(std::swap、一些容器操作)将不会采用最有效的路径(或者不会提供最好的异常保证)。基本上任何在你的函数上使用noexcept
operator的地方(截至目前)都会强制你使用noexcept
specifier。
noexcept
如果您不信任您的函数所做的调用并且宁愿死而不是让它表现出意外,请使用
纯虚函数——通常你不相信实现这些接口的人。购买保险通常是有意义的(通过指定noexcept
)
那么,还能怎么noexcept
设计呢?
我会使用两个不同的关键字——一个用于声明承诺,另一个用于执行承诺。例如noexcept和force_noexcept。事实上,实际上并不需要强制执行——它可以通过 try/catch + terminate() 来完成(是的,它会展开堆栈,但谁在乎它后面是否跟着std::terminate()?)
我会强制编译器分析给定函数中的所有调用以确定它是否可以抛出。如果确实如此,并且做出了 noexcept 承诺 - 将发出编译器错误
对于可以抛出的代码,但您知道它不应该有一种方法来确保编译器它是好的。像这样:
vector<int> v;
v.reserve(1);
...
nothrow { // memory pre-allocated, this won't throw
v.push_back(10);
}
如果承诺被破坏(即有人更改了矢量代码,现在它提供了其他保证)——未定义的行为。
免责声明:这种方法可能太不切实际了,谁知道......