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

时间:2012-01-11 08:36:59

标签: c++ algorithm memory memory-management stl

我使用visual studio 2010,其stl实现来自dinkumware

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

  1. 对于标量类型,它最终转发调用memmove
  2. 对于非标量类型,它将调用包含类型的复制构造函数。
  3. 我知道对于非标量类型,逐位应对并不安全,但在这种情况下我感到困惑,因为旧对象很快就会被破坏。看起来所有类型的按位应对是安全的,因此在_Uninitialized_move之后我们只需要免费的原始缓冲区。这将为非平凡的对象节省大量的复制构造函数和析构函数。

    那么,只为非标量类型移动内容是否安全?

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

在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,具体取决于类型是否可以简单地移动构造,并且只留下有趣的分支。

答案 2 :(得分:1)

没有。如果他们有相互指针,那么简单的逐位移动将使这些无效。