在我看来,似乎是协议,当移动构造函数为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) 我们有这种情况,并想知道解决它的最佳方法
template<typename T>
struct A : T {
A(T &&t) noexcept(noexcept(T(std::move(t))))
:T(std::move(t))
{ }
};
Run Code Online (Sandbox Code Playgroud)
遗憾的是,这无法编译,因为T的移动构造函数受到保护,我们只允许在构造函数初始化列表中调用它*this.有什么办法使这项工作或甚至有一个标准的方法呢?
根据C++标准,类构造函数的noexcept noexcept-specification究竟适用于什么?
换句话说,noexcept noexcept规范包含了上述哪一项(例如,std::terminate()在抛出异常时触发noexcept(true))?
请提供该标准的参考.关于使用noexcept构造函数的任何警告的提示也是受欢迎的.谢谢!
考虑这两个可能的类定义:
图表A:
struct A
{
A() = delete;
};
Run Code Online (Sandbox Code Playgroud)
图表A':
struct A
{
A() noexcept = delete;
}
Run Code Online (Sandbox Code Playgroud)
声明删除的函数是否有任何意义noexcept?
我已经为某些C库实现了C++绑定.库API调用可能会失败,但显然不能抛出任何东西; 为了这个问题的目的,我的绑定都是内联的.
现在,对于我的大多数内联函数/方法,编译器可以弄清楚不能抛出异常; 例如,假设我有:
bool foo() {
auto result = wrapped_lib_foo();
return some_constexpr_nothrow_cond(result);
}
Run Code Online (Sandbox Code Playgroud)
我应该用这样的功能/方法标记noexcept吗?
笔记:
请考虑以下代码段:
void f();
void a() { f(); }
void b() noexcept { f(); }
Run Code Online (Sandbox Code Playgroud)
在上面的场景f中,当前转换单元中的编译器看不到正文.因此,由于b已标记noexcept,因此必须在调用方生成其他代码,以确保捕获并std::terminate调用异常.
这就是clang++ -Ofast -std=c++2a做(主干版本):
a(): # @a()
jmp f() # TAILCALL
b(): # @b()
push rax
call f()
pop rax
ret
mov rdi, rax
call __clang_call_terminate
__clang_call_terminate: # @__clang_call_terminate
push rax
call __cxa_begin_catch
call std::terminate()
Run Code Online (Sandbox Code Playgroud)
但是,g++ -Ofast -std=c++2a不(主干版):
a():
jmp f()
b():
jmp f()
Run Code Online (Sandbox Code Playgroud)
怎么g++逃避这个?不应该在调用方生成代码,因为主体f不可见? …
class C
{
public:
C(C&&) = default; // (1)
C& operator=(C&&) = default; // (1)
C(C&&) noexcept = default; // (2)
C& operator=(C&&) noexcept = default; // (2)
}
Run Code Online (Sandbox Code Playgroud)
据我所知,如果移动构造函数/赋值运算符是由用户隐式生成或显式默认的(1),编译器将noexcept根据类的所有成员是否noexcept为移动操作提供保证来决定是否应该使用这些特殊成员函数。但是,如果我想使用默认移动特殊成员并强制它们不noexcept考虑移动操作的底层成员异常保证,该怎么办?(1)和声明之间的编译器有什么区别吗(2)?
使用标准容器成员对类实现移动操作的惯用方法不能noexcept,因此不能通过类似的操作移动vector.push_back().还是我弄错了?
为了加快速度
vector<Elem> data;
// ...
data.push_back( elem );
Run Code Online (Sandbox Code Playgroud)
我们鼓励我们进行移动操作noexcept- 因此在向量调整大小期间,库可以安全地将元素移动到重新分配的存储.
class Elem {
// ...
Elem(Elem&&) noexcept; // noexcept important for move
Elem& operator=(Elem&&) noexcept; // noexcept important for move
};
Run Code Online (Sandbox Code Playgroud)
到目前为止一切顺利,现在我的elems可以更快地被推回.
但是:如果我添加一个容器作为成员,我的班级仍可以标记为noexcept-move吗?所有标准容器都没有移动noexcept!
class Stuff {
vector<int> bulk;
// ...
Stuff(Stuff&& o) // !!! no noexcept because of vector-move
: bulk(move(o.bulk))
{}
Stuff& operator=(Stuff&&) // !!! no noexcept...
{ /* appropriate implementation */ }
};
Run Code Online (Sandbox Code Playgroud)
这也意味着,我们也可以不依赖编译器生成的移动操作,对吧?以下完整的类也没有noexcept …
请考虑以下代码段:
template<class Tuple>
class vector
{
public:
typename Tuple::size_type size() const noexcept(noexcept(m_elements.size())) {
return m_elements.size();
}
private:
Tuple m_elements;
};
class tuple
{
public:
using size_type = std::size_t;
size_type size() const { return 0; }
size_type size() noexcept { return 0; }
};
int main()
{
vector<tuple> x;
static_assert(noexcept(x.size()), "x.size() might throw");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
m_elements在说明noexcept符中使用成员变量是合法的吗?GCC 5.2(C++ 17)产生的编译器错误 m_elements未在此范围内声明.而clang 3.6(C++ 17)编译时没有任何错误.
如果我改用,两个编译器都不会产生错误noexcept(std::declval<Tuple const&>().size()).但是,正如您所看到的,我创建了一个简单的示例类tuple,无论是否Tuple具有合格的重载都至关重要size.
从我的角度来看,它更直观, …
C++ 17补充说std::uninitialized_move,但没有内部std::uninitialized_move_if_noexcept使用std::move_if_noexcept.在我看来,这将是有用的,因为现在,如果我们想要重新分配,我们仍然需要写一些东西
if constexpr (!std::is_nothrow_move_constructible_v<value_type>
&& std::is_copy_constructible_v<value_type>)
std::uninitialized_copy(...);
else
std::uninitialized_move(...);
Run Code Online (Sandbox Code Playgroud)
有没有特别的原因为什么std::uninitialized_move_if_noexcept没有在C++ 17中引入?
c++ ×10
noexcept ×10
c++11 ×6
c++17 ×2
c++14 ×1
constructor ×1
containers ×1
exception ×1
inheritance ×1
move ×1
protected ×1