是否定义了容器实现的move-constructors 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 ++版本19.00.23506 for x64:
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 ++版本19.00.23506 for x64:
Vector Stack: 1
Vector Queue: 1
答案 0 :(得分:2)
stack
和queue
不是容器;它们是容器适配器。他们使用您将其作为模板参数提供的容器类型。默认情况下,他们使用std::deque
。
因此,他们转发他们正在适应的容器的noexcept行为。因此,如果移动实际上,容器适配器不会转发noexcept他们的组件容器的行为。或者至少,它们不是标准要求的。deque
,那么使用stack
的{{1}}也是如此。
至于实际容器的noexcept状态,deque
需要vector
移动(这是C ++ 17的更改;以前没有要求)。其余的是依赖于实现的。
答案 1 :(得分:2)
只保证vector
移动构造函数noexcept
并且仅从C ++ 17开始。
deque
,stack
和queue
移动构造函数不是noexcept
。
LLVM的实现是noexcept
的事实是一个很好的补充,它与标准不矛盾。
你可能想要查看deque::swap()
,它提供类似的功能,并且是noexcept
(也是自C ++ 17以来)。