std::vector中未初始化的移动
uninitialized move in std::vector
我使用visual studio 2010,它的stl实现来自纯粹的
我注意到,当向量的内部缓冲区增长时,会调用_Uninitialized_move。这很像std::uninitialized_copy。
- 对于标量类型,它最终将调用转发到memmove
- 对于非标量类型,它将调用包含类型的复制构造函数
我知道对于非标量类型,逐位处理是不安全的,但在这种情况下我会感到困惑,因为旧对象很快就会被销毁。看起来所有类型的逐位处理都是安全的,因此我们只需要在_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
,这取决于该类型是否是平凡的可移动构造类型,并且只留下感兴趣的分支。
否。如果它们有指向彼此的指针,那么简单的逐位移动将使这些指针无效。
相关文章:
- 直接初始化不可复制、不可移动的成员,而不使用聚合初始化
- 条件跳转或移动取决于 std::wistringstream 的未初始化值
- 可视化C++将分配移动到未初始化的对象?
- C++模板成员初始化:用右值移动构造,但用左值移动引用
- 初始化不可移动对象数组:为什么这样的代码无法在 GCC 上编译?
- 如何初始化非静态模板成员变量从临时工开始,即而无需复制或移动
- Clang-Tidy:移动构造函数通过调用复制构造函数来初始化类成员
- Valgrind:使用atomic::compare_exchange_weak时,条件跳转或移动取决于未初始化的值
- 回文程序和条件跳转或移动取决于未初始化的值
- 如何编写移动构造函数以处理非初始化的移动
- 为什么'std::p air'允许使用用户定义的已删除移动构造函数从类类型的右值初始化?
- 初始化不可复制、不可移动、显式构造类型的成员数组
- 在MSVC上的数组初始化期间,destructor在不复制或移动构造方的情况下调用
- 初始化 std::数组而不复制/移动元素
- 从向量移动初始化priority_queue
- 初始化不可复制和不可移动类的元组
- 有没有一种方法可以在不使用std ::移动的情况下初始化类构建类的类
- 优雅的方式,将初始化器移动到有条件的循环后面
- 为什么添加移动构造函数禁用初始化列表
- 移动初始化列表的元素是安全的吗?