不同编译器中std容器的不同noexcept属性

3
移动构造函数是否有容器内实现定义的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(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适用于x64:

Vector Stack: 1
Vector Queue: 1
2个回答

2

stackqueue不是容器,它们是容器适配器。它们使用你提供的容器类型作为模板参数。默认情况下,它们使用std::deque

因此,它们转发所适配容器的noexcept行为。因此,如果deque在移动时抛出异常,则使用dequestack也会抛出异常。实际上,容器适配器不会转发其组件容器的noexcept行为。或者至少,标准并没有要求。

至于实际容器的noexcept状态,要求vector具有noexcept移动(这是C++17的更改;以前没有要求)。其余的则取决于实现。


2
只有C++17及以上版本中,vector的移动构造函数是保证noexcept的。 dequestackqueue的移动构造函数不是noexcept的。 LLVM实现的noexcept是一个很好的补充,不违反标准。
你可能需要查看deque::swap(),它提供类似的功能,并且是noexcept的(自C++17起)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接