std::vector::擦除异常安全
std::vector::erase exception safety
我读到std::vector era方法仅在已知类型由于强大的异常安全性而不发出异常时才使用移动操作。其他评论是擦除方法保证基本或无抛出异常安全性,具体取决于元素构造函数是否抛出。我无法在我的C++11草案中澄清这一点。我做了测试,它显示了基本的异常安全保证,它还使用了未标记为noexcept的移动构造函数。我忽略了什么吗?什么是对的?
表 100 -- 第 23.2.3 节 [sequence.reqmts] 中的序列容器要求说:
a.erase(q)
要求:对于
vector
和deque
,T
应MoveAssignable
。
这意味着实现不能对T
调用任何操作,除非销毁它或移动分配它。 请注意,如果实现移动分配T
并不能保证将调用移动分配运算符。 例如,T
可能没有移动赋值运算符,因此在这种情况下可以调用复制赋值运算符。 但是,该实现不允许复制分配T
,只能移动分配它。
*i = std::move(*j); // implementation can do this
*i = *j; // implementation can not do this
此外,23.3.6.5 矢量修饰符 [vector.modifiers] 表示如下:
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
抛出我:除非复制构造函数、移动构造函数、赋值运算符或移动赋值引发异常,否则不抛出任何内容
T
的运营商 .
必须承认,当我读到这里时,我叹了口气。 这里显然有一个小缺陷。 不允许此操作形成任何直接构造T
的表达式。 也许一个被构造为T
赋值运算符中的实现细节,但这与这个规范无关。 问题是这个表达式是否抛出:
*i = std::move(*j); // implementation can do this. Will it throw?
如果该表达式(其中i
和j
是引用T
的迭代器)不抛出,则vector::erase
具有不抛出保证。 否则vector::erase
具有基本的异常安全保证。
请注意,对于此操作,如果 is_nothrow_move_assignable<T>::value
为 false,则不允许实现回退到复制分配。 这种逻辑存在于其他vector
操作中,例如 push_back
,但在这里不存在。
另请注意同一部分的复杂性规范:
复杂性:
T
的析构函数称为等于擦除元素数的次数,但移动赋值T
运算符称为等于 元素在擦除的元素之后的矢量中。
重述:如果擦除一系列以向量结尾结尾的元素,将执行零移动分配,并且移动分配是唯一可能抛出的内容。 因此,如果您在最后擦除,即使is_nothrow_move_assignable<T>::value
是假的,您也会得到不扔的保证。
23.3.6.5 抛出:除非 T 的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符抛出异常,否则不抛出任何异常。
如果您的实现符合此要求,它可能会根据需要实现擦除。据我所知,没有隐含的异常安全保证。
- C++代码中的异常安全
- 编写"anti-lack of memory"异常安全代码
- std:string::substr 异常安全吗?
- 如何以异常安全的方式使用放置新?
- 通过引用从 c++ 函数异常返回对象是否安全
- 异常安全服务器
- 实现 std::vector::p ush_back 强异常安全
- 标准::unique_ptr和异常安全
- 如何使用QThreads使无锁生产者-消费者线程交换更加异常安全
- 使功能异常安全
- 与构造函数参数相关的异常安全的习语
- uninitialized_copy() 异常安全吗?
- 为什么我们需要 RAII 来解决异常安全问题
- 异常安全构造函数
- 关于 swap() 操作的异常安全 - 这有什么问题?
- std::vector::擦除异常安全
- 异常安全 - 用于可靠回滚对象状态的模式
- 异常安全的 for 循环
- 异常安全代码和移动语义
- 向量::插入的异常安全保证是什么?