C++ Visual Studio 2015附带的std::vector实现的异常安全性

C++ Visual Studio 2015附带的std::vector实现的异常安全性,c++,vector,visual-studio-2015,stl,c++14,C++,Vector,Visual Studio 2015,Stl,C++14,考虑以下计划: #include <iostream> #include <vector> #include <type_traits> struct X { int state; X() : state(0) {}; X(int x) : state(x) {}; X(X const& y) noexcept : state(1) {} X(X&& y) noexcept(false) : st

考虑以下计划:

#include <iostream>
#include <vector>
#include <type_traits>
struct X
{
    int state;
    X() : state(0) {};
    X(int x) : state(x) {};
    X(X const& y) noexcept : state(1) {}
    X(X&& y) noexcept(false) : state(y.state != 8 ? 2 : throw 1) 
    { y.state = 0; }
    X& operator =(X const&) = default;
    X& operator =(X&&) = default;
};
int main() {
    std::vector<X> a;
    a.reserve(2u);
    a.emplace_back(6);
    a.emplace_back(8);
    try { 
        // ####
        std::cout << 'A' << a.front().state << a.back().state;
    }
    catch (...) 
    { 
        std::cout << 'B' << a.front().state << a.back().state;
    }
    return 0;
}
那么,为什么我希望在所有情况下都是
A11

1:
a.resize(10u,X{})

[vector.capacity],n4140和n4606的16/17表示关于
空隙大小调整(尺寸类型sz,常数T&c)

要求:
T
可插入
*此

备注:如果引发异常,则不会产生任何影响

因此,如果编译器必须保证在异常情况下可以完全回滚(“无效果”),那么它必须复制元素,或者只能在移动不异常的情况下移动,因为移动会立即影响无法回滚的元素(这只有在moving将抛出时才有必要,而noexcept move构造函数则不是这样)

因此,我希望
A11
作为输出(或者
B68
,如果复制构造函数抛出)

2:
xb;a.向后推(b);

3:
a.emplace_back(1);

n4140和n4606中的[vector.modifiers]一个表示:

如果在末尾插入单个元素时引发异常,并且
T
CopyInsertable
是\u nothrow\u move\u constructible::value
true
,则不会产生任何影响

同样,当类型为“CopyInsertable”(X为CopyInsertable)时,如果出现异常,标准要求“无效”。->如果没有异常,则移动

我对这些指令的解释是,
A11
是预期的输出(或者换句话说,一致的std::vector不应该移动它的元素,除非移动不是例外或者复制是不可能的)

我试图查找有关VS SL的一些信息,但在VS博客上只找到一篇博客文章“”,表明VS标准库实现是“功能完整的”,我不知道这是否应该声称符合标准

注意:我怀疑我是第一个发现VS在实际复制元素时错误地移动了元素的人——如果有人有连接问题,不要避免指向它


因此,问题是:MSVC中的行为是否有特定的原因(即复制与移动或其他任何操作以外的性能影响),或者这是否是一个bug?

是否是:state(state!=8?2:throw 1)
在初始化之前访问
state
时导致UB?您是否打算编写
X(X&&X)noexcept(false):state(x.state!=8?2:throw 1){}
@SimonKraemer:的确:)看起来像个bug。你可以检查向量实现,看看它是如何完成的。在libstd++中,它们有一个
\u move\u if\u noexcept
(或类似的东西)复制而不是移动移动将抛出的位置。@Arunmu:据我所知,MSVC使用
std::memmove
来处理普通类型或
\u Al.construct(\u undance(\u Dest),\u std move(*\u First))
在一般情况下,如果没有异常,它应该是移动的。嗯,不确定这是否是一个错误。根据与
std:vector一起使用的类型,它必须是可移动的,这似乎定义为
tu=rv;u等于构建之前的rv值
(有关更多示例,请参阅链接文档)您的
状态
未实现。此外,在
末尾插入单个元素时不会引发异常。
    statement               g++     msvc    expected

1   a.resize(10u, X{});     A11     B08     A11
2   X b; a.push_back(b);    A11     B08     A11
3   a.emplace_back(1);      A11     B08     A11