不同编译器中标准容器的不同 noexcept 属性
Different noexcept property for std containers in different Compilers
是否定义了容器实现的移动构造函数noexcept
属性?我刚刚发现以下内容在 clang 中有效,但在 gcc 或 msvc++ 中无效:
std::vector<std::vector<std::unique_ptr<int>>> vector_a;
std::vector<std::stack<std::unique_ptr<int>>> vector_b;
vector_a.reserve(10); // this works in all tested compilers
vector_b.reserve(10); // this only works in clang
我的问题是,这是由于标准实施不完整造成的,还是根本没有定义(故意?)。
我测试了一些标准容器:
#include <iostream>
#include <deque>
#include <vector>
#include <queue>
#include <stack>
int main() {
std::cout << "Deque: " << std::is_nothrow_move_constructible<std::deque<float>>::value << std::endl;
std::cout << "Vector: " << std::is_nothrow_move_constructible<std::vector<float>>::value << std::endl;
std::cout << "Queue: " << std::is_nothrow_move_constructible<std::queue<float>>::value << std::endl;
std::cout << "Stack: " << std::is_nothrow_move_constructible<std::stack<float>>::value << std::endl;
}
gcc 7.2.1:
Deque: 0
Vector: 1
Queue: 0
Stack: 0
clang 5.0.0:
Deque: 1
Vector: 1
Queue: 1
Stack: 1
Microsoft C/C++ x64 版本 19.00.23506:
Deque: 0
Vector: 1
Queue: 0
Stack: 0
编辑
使用向量作为底层容器的队列和堆栈的结果:
std::cout << "Vector Stack: " << std::is_nothrow_move_constructible<std::stack<float, std::vector<float>>>::value << std::endl;
std::cout << "Vector Queue: " << std::is_nothrow_move_constructible<std::queue<float, std::vector<float>>>::value << std::endl;
gcc 7.2.1:
Vector Stack: 1
Vector Queue: 1
clang 5.0.0:
Vector Stack: 1
Vector Queue: 1
Microsoft C/C++ x64 版本 19.00.23506:
Vector Stack: 1
Vector Queue: 1
stack
和 queue
不是容器;它们是容器 适配器 。他们使用 你给他们的容器类型作为模板参数。默认情况下,他们使用 std::deque
.
因此,他们转发他们正在适配的容器的 noexcept 行为。因此,如果 deque
在移动时抛出,那么使用 deque
. 的 stack
也会抛出。实际上,容器适配器 不会 转发其组件容器的 noexcept 行为。或者至少,标准不需要它们。
至于实际容器的 noexcept 状态,vector
需要进行 noexcept
移动(这是 C++17 的更改;之前没有要求)。其余的取决于实现。
只保证 vector
的移动构造函数 noexcept
并且仅从 C++17 开始。
deque
, stack
and queue
移动构造函数不是 noexcept
。
LLVM 的实现是 noexcept
这一事实是一个很好的补充,它与标准不矛盾。
您可能想查看 deque::swap()
,它提供了类似的功能并且是 noexcept
(也是自 C++17 起)。
是否定义了容器实现的移动构造函数noexcept
属性?我刚刚发现以下内容在 clang 中有效,但在 gcc 或 msvc++ 中无效:
std::vector<std::vector<std::unique_ptr<int>>> vector_a;
std::vector<std::stack<std::unique_ptr<int>>> vector_b;
vector_a.reserve(10); // this works in all tested compilers
vector_b.reserve(10); // this only works in clang
我的问题是,这是由于标准实施不完整造成的,还是根本没有定义(故意?)。
我测试了一些标准容器:
#include <iostream>
#include <deque>
#include <vector>
#include <queue>
#include <stack>
int main() {
std::cout << "Deque: " << std::is_nothrow_move_constructible<std::deque<float>>::value << std::endl;
std::cout << "Vector: " << std::is_nothrow_move_constructible<std::vector<float>>::value << std::endl;
std::cout << "Queue: " << std::is_nothrow_move_constructible<std::queue<float>>::value << std::endl;
std::cout << "Stack: " << std::is_nothrow_move_constructible<std::stack<float>>::value << std::endl;
}
gcc 7.2.1:
Deque: 0
Vector: 1
Queue: 0
Stack: 0
clang 5.0.0:
Deque: 1
Vector: 1
Queue: 1
Stack: 1
Microsoft C/C++ x64 版本 19.00.23506:
Deque: 0
Vector: 1
Queue: 0
Stack: 0
编辑
使用向量作为底层容器的队列和堆栈的结果:
std::cout << "Vector Stack: " << std::is_nothrow_move_constructible<std::stack<float, std::vector<float>>>::value << std::endl;
std::cout << "Vector Queue: " << std::is_nothrow_move_constructible<std::queue<float, std::vector<float>>>::value << std::endl;
gcc 7.2.1:
Vector Stack: 1
Vector Queue: 1
clang 5.0.0:
Vector Stack: 1
Vector Queue: 1
Microsoft C/C++ x64 版本 19.00.23506:
Vector Stack: 1
Vector Queue: 1
stack
和 queue
不是容器;它们是容器 适配器 。他们使用 你给他们的容器类型作为模板参数。默认情况下,他们使用 std::deque
.
因此,他们转发他们正在适配的容器的 noexcept 行为。因此,如果 的 deque
在移动时抛出,那么使用 deque
.stack
也会抛出。实际上,容器适配器 不会 转发其组件容器的 noexcept 行为。或者至少,标准不需要它们。
至于实际容器的 noexcept 状态,vector
需要进行 noexcept
移动(这是 C++17 的更改;之前没有要求)。其余的取决于实现。
只保证 vector
的移动构造函数 noexcept
并且仅从 C++17 开始。
deque
, stack
and queue
移动构造函数不是 noexcept
。
LLVM 的实现是 noexcept
这一事实是一个很好的补充,它与标准不矛盾。
您可能想查看 deque::swap()
,它提供了类似的功能并且是 noexcept
(也是自 C++17 起)。