我已经读过std :: vector erase方法只有在已知类型由于强异常安全性而不发出异常时才使用移动操作。其他注释是擦除方法保证基本或不抛出异常安全,具体取决于元素构造函数是否抛出。在我的C ++ 11草案中,我无法澄清这一点。我做了测试,它显示了基本的异常安全保证,它也使用了未标记为noexcept的移动构造函数。我忽略了什么吗?什么是对的 ?
答案 0 :(得分:3)
表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
为假,如果您在最后删除,也会获得无抛出保证。
答案 1 :(得分:1)
23.3.6.5抛出:除非复制构造函数,移动构造函数,赋值运算符或T的移动赋值运算符抛出异常,否则无效。
如果您的实现符合此要求,它可以在其认为合适时实现擦除。据我所知,没有隐含的异常安全保证。