从N3797开始,swap除非另有说明,否则C++标准要求容器函数不抛出任何异常[container.requirements.general](23.2.1§10).
swap指定的成员函数不抛出未声明noexcept?同样的问题适用于专门的非成员swap重载.
关于使用noexcept需要多少关注的问题,正在进行一场辩论.我们都知道noexcept对于编译器的优化器并没有真正做大量的事情,除了外部定义的代码,编译器否则必须假设它可以抛出,因为它无法知道它的实现,因此标记事物的唯一真正的其他性能优势noexcept用于使用std :: move_if_noexcept <>的代码,假定它主要是STL容器及其算法.
因此,该评估将是这样的:你不能使用noexcept,除非:
extern函数和类,其中编译器不知道可调用的实现.
移动构造函数,移动赋值运算符并交换可能包含在STL容器中的任何类型.
否则不要担心.
这是一个公平的评估吗?STL中还有其他地方可以产生更优化的代码吗?如果是这样,哪个STL实现是这个,什么需要标记为no,除了它工作,以及什么性能的好处导致(更少的内存分配,更低的复杂性)?
编辑:使CashCow建议更改措辞.
例如,有两种不同的方法来访问私有数组的元素,重载数组下标运算符或定义at:
T& operator[](size_t i) { return v[i]; }
T const& operator[](size_t i) const { return v[i]; }
T& at(size_t i)
{
if (i >= length)
throw out_of_range("You shall not pass!");
return v[i];
}
T const& at(size_t i) const
{
if (i >= length)
throw out_of_range("You shall not pass!");
return v[i];
}
Run Code Online (Sandbox Code Playgroud)
该at版本可以抛出异常,但数组下标运算符不能.
我的问题是,尽管operator[]没有抛出异常,它是否可以被标记为noexcept甚至知道它可以引发SIGSEGV信号,还是只是一种不好的做法?
我想指出一个信号(如SIGSEGV)也不例外.作为文字解释noexcept意义,一个noexcept功能是声称它不会抛出异常.它什么也没说(包括信号).
但是,noexcept函数具有更多的意义,至少对于我的代码的客户而言.noexcept也隐含地说这个函数是安全的,它会在没有计算错误的情况下完成它的执行.
那么,标记noexcept一个不安全的功能是不合适的呢?
我曾经看过斯科特迈尔斯上GoingNative2013谈话'的有效C++ 11月14日采样器’,并解释说,他使用的std::move_if_noexcept.
所以我认为还应该std::forward_if_noexcept保证例外安全forward吗?为什么标准库中没有这样的内容?还有其他可能保证吗?
我不确定这是GCC编译器的错误还是预期的行为noexcept.
请考虑以下示例:
struct B {
B(int) noexcept { }
virtual void f() = 0;
};
struct D: public B {
using B::B;
D() noexcept(noexcept(D{42})): B{42} { }
void f() override { }
};
int main() {
B *b = new D{};
}
Run Code Online (Sandbox Code Playgroud)
如果noexcept删除它,它编译.
无论如何,正如在例子中,我从GCC v5.3.1得到了这个错误:
test.cpp:8:31: error: invalid use of incomplete type ‘struct D’
D() noexcept(noexcept(D{42})): B{42} { }
^
Run Code Online (Sandbox Code Playgroud)
据我所知,struct D不是一个不完整的类型,但继承构造函数涉及到语句,看起来编译器实际上考虑的是基本结构的完整性而B不是D.
这是预期的行为还是合法代码?
为清楚起见:
noexcept如果您的实现具有零成本(如果没有抛出)异常模型,说明符是否无用?什么是缺乏noexcept有后果的例子?
当C++ 11 inline调用使用noexcept限定符声明的其他函数时,C++ 11是否对函数或方法提供任何保证?
class My_String { ...
const char * c_str () const noexcept;
inline operator const char * () const { return c_str(); }
};
Run Code Online (Sandbox Code Playgroud)
我假设优化编译器可以自由地实现内联方法,而没有完整的EH和堆栈展开,根据noexcept资格.我也希望这也是一个简单的访问方法:
... inline operator const char * () const { return m_buffer; }
Run Code Online (Sandbox Code Playgroud)
虽然这个例子看起来微不足道,但异常保证在用于实现其他类或函数时很重要.问: C++ 11标准是否解决了这个问题,还是应该标记内联方法noexcept?或者noexcept除非需要匹配类或函数规范,否则最好省略?
编辑:为避免一些混淆:noexcept内联方法是隐式的吗?
在更有效的C++中,Scott Meyers说
C++指定复制作为异常抛出的对象.
我想,如果复制构造函数依次抛出异常,std::terminate则会调用,所以这是声明所有异常的复制构造函数的一个很好的理由noexcept(而且,我想,不要抛出从堆中分配内存的对象,喜欢std::string).
然而,我惊讶地发现GCC 4.7.1附带的标准库实现没有为std::bad_alloc和定义那些复制构造函数std::exception.他们不应该定义它们noexcept吗?
我想这样做:
using function_type = void (*)(void*)noexcept;
Run Code Online (Sandbox Code Playgroud)
但是我收到错误"类型别名中不允许出现异常规范." (Xcode 6.1版中的clang)
有没有使用noexcept说明符创建别名的解决方法?
我正在寻找一些适用于跨平台功能的语言(不是扩展)定义的东西.
在我看来,似乎是协议,当移动构造函数为noexcept(false)时,标准库必须调用复制构造函数而不是移动构造函数.
现在我不明白为什么会这样.此外,Visual Studio VC v140和gcc v 4.9.2似乎也有不同的做法.
我不明白为什么除了这是例如矢量的关注.我的意思是如果T没有,vector :: resize()应该如何能够提供强大的异常保证.正如我所看到的那样,矢量的异常级别将取决于T.无论是否使用复制或移动.我理解noexcept只是对编译器进行异常处理优化的眨眼.
当使用Visual Studio编译时,这个小程序在使用gcc编译时调用复制构造函数并移动构造函数.
include <iostream>
#include <vector>
struct foo {
foo() {}
// foo( const foo & ) noexcept { std::cout << "copy\n"; }
// foo( foo && ) noexcept { std::cout << "move\n"; }
foo( const foo & ) { std::cout << "copy\n"; }
foo( foo && ) { std::cout << "move\n"; }
~foo() noexcept {}
};
int main() {
std::vector< foo > v;
for ( int i = 0; …Run Code Online (Sandbox Code Playgroud)