将std :: vector >移动到std :: vector >
问题描述:
有时会出现这样的情况:我们有一个工厂生成std :: unique_ptr向量,稍后我们想要在类/线程之间共享这些指针/你的名字。所以最好使用std :: shared_ptr代替。当然还有一种方式转换的std :: uniqe_ptr到std :: shared_ptr的将std :: vector <std :: unique_ptr <T>>移动到std :: vector <std :: shared_ptr <T>>
std::shared_ptr<int> sharedV;
std::unique_ptr<int> uniqueV(new int(2));
sharedV = std::move(uniqueV);
那么,有没有简单的方法做这样的事情性病收藏?
答
您可以使用<algorithm>
中的std::move
来移动范围。它的行为与std::copy
很相似,但会改为移动。以下示例将将所有unique_ptr
从uniqueV
移至sharedV
。在示例结束时,uniqueV
的元素将全部为nullptr
。
#include <algorithm>
#include <iterator>
#include <memory>
#include <vector>
int main()
{
std::vector<std::shared_ptr<int>> sharedV;
std::vector<std::unique_ptr<int>> uniqueV;
uniqueV.emplace_back(std::make_unique<int>(42));
std::move(uniqueV.begin(), uniqueV.end(), std::back_inserter(sharedV));
return 0;
}
答
要添加上的François Andrieux's answer顶部,std::vector
具有介于insert()
成员函数。正好路过的迭代器到你的unique_ptr
载体将无法正常工作,但有一种方法对那些迭代器反引用转换从左值到xvalues:std::move_iterator
及其对应的工厂函数:std::make_move_iterator
:
sharedV.insert(sharedV.end(),
std::make_move_iterator(uniqueV.begin()),
std::make_move_iterator(uniqueV.end()));
的原因,这可能比使用std::back_inserter
效率更高insert()
会知道结果的大小是多少,所以最多只需要完成一次分配,然后实际插入都不需要进行大小检查。
这是使劲儿写,我会建议的这个命名extend()
基于范围的重载:
template <class T, class Range>
void extend(std::vector<T>& dst, Range&& range) {
using std::begin; using std::end;
if constexpr (std::is_lvalue_reference<Range>{}) {
dst.insert(dst.end(), begin(range), end(range));
} else {
dst.insert(dst.end(),
std::move_iterator(begin(range)), std::move_iterator(end(range)));
}
}
这是C++ 17,但在C++ 14容易可行。只需要更多的打字。然后你会写:
extend(sharedV, std::move(uniqueV));
*所以这将是可取的使用std :: shared_ptr代替*这些事情需要参与所有权吗?如果没有,你可以通过引用传递向量。 – NathanOliver
@NathanOliver对于某些我们希望共享这些指针所有权的特定情况,我们期望这样做。不要过分:) – Amadeusz