c++ - 面对抛出移动构造函数/赋值运算符,std::vector::emplace() 是否真的提供了强大的异常保证?

标签 c++ c++11 vector libstdc++

According to cppreference.com , std::vector::emplace() 无条件提供强异常保证:

If an exception is thrown (e.g. by the constructor), the container is left unmodified, as if this function was never called (strong exception guarantee).

但是,在 GCC 7.1.1 的实践中似乎并非如此。以下程序:

#include <iostream>
#include <vector>

struct ugly
{
  int i;

  ugly(int i) : i{i} { }

  ugly(const ugly& other) = default;

  ugly& operator=(ugly&& other) {
    if (other.i == 3) {
      throw other.i;
    }
    i = other.i;
    return *this;
  }

  ugly& operator=(const ugly& other) = default;
};

int main() {
  std::vector<ugly> vec;
  vec.reserve(6);
  vec.emplace_back(0);
  vec.emplace_back(1);
  vec.emplace_back(2);
  vec.emplace_back(4);
  vec.emplace_back(5);

  try {
    vec.emplace(vec.begin() + 3, 3);
  } catch (int i) {
  }

  for (const auto& u : vec) {
    std::cout << u.i << "\n";
  }

  return 0;
}

打印

0
1
2
4
4
5

事实上,如果允许复制/移动抛出异常,我很难看出 emplace() 如何提供强有力的保证。要放置在中间,我们必须先将一堆元素移开,然后在其位置构建新元素。如果其中任何一个抛出,我们必须将所有其他元素移回它们原来的位置,但这些移动也可以抛出!

那么谁错了,是 cppreference 还是 gcc?

最佳答案

根据 C++14 标准,强异常保证仅在您插入的类型本身具有强异常保证时才有效。

这里:

23.3.6.5 vector modifiers [ vector.modifiers ]

iterator insert(const_iterator position, const T& x);
iterator insert(const_iterator position, T&& x);
iterator insert(const_iterator position, size_type n, const T& x);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, initializer_list<T>);
template <class... Args> void emplace_back(Args&&... args);
template <class... Args> iterator emplace(const_iterator position, Args&&... args);
void push_back(const T& x);
void push_back(T&& x);

1 Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid. If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. If an exception is thrown while inserting a single element at the end and T is CopyInsertable or is_nothrow_move_constructible::value is true, there are no effects. Otherwise, if an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified.

所以它看起来像cppreference.com是错误的。

关于c++ - 面对抛出移动构造函数/赋值运算符,std::vector::emplace() 是否真的提供了强大的异常保证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45125134/

相关文章:

matlab - 在 Octave 中加载输入文件并创建向量和矩阵

c++ - 如何处理静态存储时长警告?

c++ - 查找 vector 是否包含第二个元素等于 X 的对

c++ - 为什么 'typeid(x) == typeid(y)'评估为true,而 'x'和 'y'分别是类型T和T&的id表达式?

c++ - 如何通过不同的类将一个 vector 复制到另一个 vector

c++ - 什么更快 : recreate or clear()?

c++ - 如何保存没有某些字符的字符串?

c++ - 如何修复 "type_info' s 具有隐藏的可见性。他们都应该有公众可见度。”?

c++ - 如何在 Crypto++ 中使用自定义 key

c++ - 如何复制一个类型?