std::vector中未初始化的移动

uninitialized move in std::vector

本文关键字:移动 初始化 vector std      更新时间:2023-10-16

我使用visual studio 2010,它的stl实现来自纯粹的

我注意到,当向量的内部缓冲区增长时,会调用_Uninitialized_move。这很像std::uninitialized_copy。

  1. 对于标量类型,它最终将调用转发到memmove
  2. 对于非标量类型,它将调用包含类型的复制构造函数

我知道对于非标量类型,逐位处理是不安全的,但在这种情况下我会感到困惑,因为旧对象很快就会被销毁。看起来所有类型的逐位处理都是安全的,因此我们只需要在_Uninitialized_move之后释放原始缓冲区。这将为非平凡对象节省大量的复制构造函数和析构函数。

那么,只移动非标量类型的内容安全吗?

如果你完全确定你移动的对象没有指向彼此的指针(包括这些对象的子对象),那么只移动内容就可以了。然而,除非你知道里面的类型是如何设计的,否则你不可能知道这一点。一个例外是,如果类型不大于指针(sizeof(Type) <= sizeof( void* )),那么在同一容器中不太可能有指向对象的指针,所以通常可以只移动它。

在C++11中,有许多特性需要知道执行位操作是否安全。

在你的情况下,我认为你应该使用std::is_trivially_move_constructible<T>。这些特性是使用编译器内部实现的(不可移植,这就是为什么它在标准库中),但它们本身是可移植的。

因此,代码应该类似于:

template <typename T>
void move_to(T* storage, T* begin, T* end) {
  if (std::is_trivially_move_constructible<T>::value) {
    memmove(storage, begin, (end - begin) * sizeof(T));
  } else {
    for (; begin != end; ++begin, ++storage) {
      new (storage) T(std::move(*begin));
    }
  }
}

编译器将在编译时优化if,这取决于该类型是否是平凡的可移动构造类型,并且只留下感兴趣的分支。

否。如果它们有指向彼此的指针,那么简单的逐位移动将使这些指针无效。