移动到未初始化的内存,或raw_storage_iterator的工作原理

时间:2015-07-18 21:27:17

标签: c++ c++11

我想将一系列对象移动到未初始化的内存中(使用move-construction)。由于std::uninitialized_copy没有移动对象,我提出了两个选项:使用std::moveraw_storage_iterator,或者使用手动循环:

T* dest = get_memory();
// option one
std::move(first, last, std::raw_storage_iterator<T*, T>(dest));
// option two
for (auto i=first; i != last; ++i, ++dest)
{
    new(dest) T(std::move(*i));
}

第一个选项是移动构造(因此等同于第二个),还是复制构造,或默认构造,然后移动赋值?是否还有其他考虑因素需要选择一个或另一个选项?

1 个答案:

答案 0 :(得分:10)

std::raw_storage_iterator在分配时使用了 placement-new 运算符,根据复制赋值运算符定义了一个const左值引用:

§20.7.10[storage.iterator] / p1:

raw_storage_iterator& operator=(const T& element);

总是调用复制构造函数(即使使用rvalue调用)。

此案例已被报告为LWG issue 2127,它通过引入另一个赋值运算符的赋值运算符来添加对可移动构造类型的支持,这意味着 可以将构造元素移动到一旦采纳拟议的变更,就会产生未初始化的记忆。在更新发生之前,您需要依靠自己的for循环。或者,您可以使用如下定义的std::uninitialized_copy算法:

§20.7.12.2[uninitialized.copy] / p1:

for (; first != last; ++result, ++first)
    ::new (static_cast<void*>(&*result))
        typename iterator_traits<ForwardIterator>::value_type(*first);

使用std::make_move_iterator辅助函数包装输入迭代器后,您将获得与手写for循环相同的效果:

std::uninitialized_copy(std::make_move_iterator(first)
                      , std::make_move_iterator(last)
                      , dest);

通过引入std::uninitialized_move来扩展算法集:

std::uninitialized_move(first, last, dst);