C++ std::vector::擦除异常安全

C++ std::vector::擦除异常安全,c++,c++11,vector,C++,C++11,Vector,我已经读到,std::vector擦除方法仅在已知类型由于强异常安全性而不发出异常时才使用移动操作。其他注释是,erase方法根据元素构造函数是否抛出来保证基本或无抛出异常安全。在我的C++11草稿中,我无法澄清这一点。我做了测试,它显示了基本的异常安全保证,它还使用了未标记为noexcept的move构造函数。我忽略了什么吗?什么是对的 23.3.6.5抛出:除非T的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符抛出异常,否则不会抛出任何内容 如果您的实现符合此要求,它可以根据需要执行

我已经读到,std::vector擦除方法仅在已知类型由于强异常安全性而不发出异常时才使用移动操作。其他注释是,erase方法根据元素构造函数是否抛出来保证基本或无抛出异常安全。在我的C++11草稿中,我无法澄清这一点。我做了测试,它显示了基本的异常安全保证,它还使用了未标记为noexcept的move构造函数。我忽略了什么吗?什么是对的

23.3.6.5抛出:除非T的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符抛出异常,否则不会抛出任何内容

如果您的实现符合此要求,它可以根据需要执行擦除。据我所知,没有隐含的异常安全保证

23.3.6.5抛出:除非T的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符抛出异常,否则不会抛出任何内容

如果您的实现符合此要求,它可以根据需要执行擦除。就我所知,没有隐含的异常安全保证。

表100——第23.2.3节[Sequence.reqmts]中的序列容器要求说明:

a.erase(q)
要求:对于
vector
deque
T
应为
可移动可分配的

这意味着该实现不能调用
T
上的任何操作,只能对其进行销毁或移动分配。注意,如果实现move赋值
T
,则不能保证调用move赋值操作符。例如,
T
可能没有移动分配运算符,因此在这种情况下可以调用复制分配运算符。但是,不允许实现复制分配
T
,只允许移动分配它

*i = std::move(*j);  // implementation can do this
*i = *j;             // implementation can not do this
此外,23.3.6.5矢量修饰符[矢量修饰符]说明如下:

iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
Throws:除非复制构造函数、移动构造函数、赋值运算符或移动赋值引发异常,否则不执行任何操作
T的运算符

我必须承认,当我读到这篇文章时,我叹了口气。这里显然有一个小缺陷。此操作不允许形成任何将直接构造
T
的表达式。也许其中一个被构造为
T
赋值运算符中的实现细节,但这与本规范无关。问题在于该表达式是否抛出:

*i = std::move(*j);  // implementation can do this. Will it throw?
如果该表达式(其中
i
j
是指
T
的迭代器)没有抛出,则
vector::erase
具有无抛出保证。否则,
vector::erase
具有基本的异常安全保证

请注意,对于此操作,如果
为\u nothrow\u move\u assignable::value
为false,则不允许实现退回到复制分配。此类逻辑存在于其他
向量
操作中,如
推回
,但不在此处

还要注意同一节的复杂性规范:

复杂性:
T
的析构函数被调用的次数等于删除的元素数,但移动赋值 调用
T
运算符的次数等于 删除元素后向量中的元素

重申:如果删除以向量结尾的一系列元素,将执行移动赋值,并且移动赋值是唯一可能抛出的内容。因此,如果您在最后进行擦除,即使
为\u nothrow\u move\u assignable::value
为false,您也可以获得不抛出保证。

第23.2.3节[Sequence.reqmts]中的表100——序列容器要求说明:

a.erase(q)
要求:对于
vector
deque
T
应为
可移动可分配的

这意味着该实现不能调用
T
上的任何操作,只能对其进行销毁或移动分配。注意,如果实现move赋值
T
,则不能保证调用move赋值操作符。例如,
T
可能没有移动分配运算符,因此在这种情况下可以调用复制分配运算符。但是,不允许实现复制分配
T
,只允许移动分配它

*i = std::move(*j);  // implementation can do this
*i = *j;             // implementation can not do this
此外,23.3.6.5矢量修饰符[矢量修饰符]说明如下:

iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
Throws:除非复制构造函数、移动构造函数、赋值运算符或移动赋值引发异常,否则不执行任何操作
T的运算符

我必须承认,当我读到这篇文章时,我叹了口气。这里显然有一个小缺陷。此操作不允许形成任何将直接构造
T
的表达式。也许其中一个被构造为
T
赋值运算符中的实现细节,但这与本规范无关。问题在于该表达式是否抛出:

*i = std::move(*j);  // implementation can do this. Will it throw?
如果该表达式(其中
i
j
是指
T
的迭代器)没有抛出,则
vector::erase
具有无抛出保证。否则,
vector::erase
具有基本的异常安全保证

请注意,对于此操作,如果
为\u nothrow\u move\u assignable::value
为false,则不允许实现退回到复制分配。此类逻辑存在于其他
向量
操作中,如
推回
,但不在此处

还要注意同一节的复杂性规范:

复杂性:
T
的析构函数被调用的次数等于删除的元素数,但移动赋值 调用
T
运算符的次数等于 删除后向量中的元素