如何在std::copy算法中使用std::make_move_iterator



我有一个问题:

当我试图用std::copy算法将数据从(vectorunique_ptr(移动到(listunique_ptr(时,算法是成功的,但在运行中会崩溃!这是一个代码:


std::vector<std::unique_ptr<std::string>> vecUPTRstring;
std::unique_ptr<std::string> ptrStringArr1(new std::string("qwe"));
std::unique_ptr<std::string> ptrStringArr2(new std::string("asd"));
vecUPTRstring.push_back(std::move(ptrStringArr1));
vecUPTRstring.push_back(std::move(ptrStringArr2));
std::list<std::unique_ptr<std::string>> listUPTRstring;
std::copy(std::make_move_iterator(vecUPTRstring.begin()),
std::make_move_iterator(vecUPTRstring.end()),
std::make_move_iterator(listUPTRstring.begin())
);
for (auto& var : listUPTRstring)
{
cout << "list value = " << var << endl;
}

崩溃错误为:

表达式:无法取消引用结束列表迭代器

我已经检查了不同的方法来修复它,并阅读了包括这篇文章在内的一些文章,但我仍然需要帮助来解决这个问题。

只让迭代器移动迭代器,而目标迭代器应该是插入器,因为您的列表是空的。如果目标容器中已经有n元素,并且希望用源元素覆盖这些元素,则只能将dest.begin()作为目标传递。

std::copy(std::make_move_iterator(vecUPTRstring.begin()),
std::make_move_iterator(vecUPTRstring.end()),
std::inserter(listUPTRstring, listUPTRstring.end()));

然而,我也必须建议使用移动迭代器的std::move而不是std::copy,因为它在语义上是相等的,而且更简单/更清晰:

std::move(vecUPTRstring.begin(),
vecUPTRstring.end(),
std::inserter(listUPTRstring, listUPTRstring.end()));

列表使用类似指针的间接方式来保存值,并且在std::list中存储类似指针的小元素几乎从未比使用向量快过,只有极少数例外。因此,首先,您应该检查使用std::list是否确实为您节省了时间。您还应该检查使用std::unique_ptr是否为您节省了时间。

只有当基准测试证明在使用间接方法时性能有所提高时,才引入间接方法默认情况下,按值将事物保持在向量中。只有当测量结果显示有好处时,才使用其他容器和内存管理层。我的意思是测量。现代CPU的性能通常受到内存访问模式的约束,并且缓存未命中可以很容易地淹没任何感知到的"错误";开销";的";"浪费";复制连续的高速缓存行。首先,顺序存储器访问是免费的。

具体到字符串,以下类型的性能从最好到最差,最后一种非常糟糕,尤其是当字符串很小时:

  • std::vector<std::string>
  • std::vector<std::unique_ptr<std::string>>
  • std::list<std::string>
  • std::list<std::unique_ptr<std::string>>

但是,如果你真的想使用列表,并在列表的生命周期中进行大量插入/删除(这是使用该数据类型的唯一原因(,那么支付将值移动/复制到列表中一次的成本,然后通过使用值而不是显式指针来享受较低间接性的好处,可能会更便宜。

无论如何,您绝对应该对所有这些进行基准测试,因为在大多数情况下,std::list在没有缓存的微控制器上是有意义的,一旦您在过去20年中某个时候制造的PC级CPU上的大型应用程序和活动堆的环境中运行,它就会变成性能灾难。

template <typename T>
std::list<T> ptrVectorToList(std::vector<std::unique_ptr<T>> && src)
{
std::list<T> list;
for (auto &ptr : src) {
list.emplace_back(std::move(*ptr));
ptr.reset();
}
src.clear();
return list;
}

最新更新