有时我们有一个工厂生成std :: unique_ptr的向量,之后我们想在类/线程之间共享这些指针/你命名它。因此,最好使用std :: shared_ptr。有一种方法可以将std :: uniqe_ptr转换为std :: shared_ptr
std::shared_ptr<int> sharedV;
std::unique_ptr<int> uniqueV(new int(2));
sharedV = std::move(uniqueV);
那么有什么简单的方法可以用std集合做这样的事情吗?
答案 0 :(得分:8)
您可以使用<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;
}
答案 1 :(得分:6)
要在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));