C++ 移动标准::向量<;标准::唯一性\u ptr<;T>&燃气轮机;到std::vector<;标准::共享\u ptr<;T>&燃气轮机;

C++ 移动标准::向量<;标准::唯一性\u ptr<;T>&燃气轮机;到std::vector<;标准::共享\u ptr<;T>&燃气轮机;,c++,c++11,stl,c++14,C++,C++11,Stl,C++14,有时,我们会有一个工厂,它生成std::unique_ptr的向量,稍后我们会在类/线程/你所说的对象之间共享这些指针。因此,最好使用std::shared\u 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::

有时,我们会有一个工厂,它生成std::unique_ptr的向量,稍后我们会在类/线程/你所说的对象之间共享这些指针。因此,最好使用std::shared\u 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::shared_ptr sharedV;
标准:唯一(新国际(2));
sharedV=std::move(uniqueV);
那么,有没有直接的方法来处理std收集

您可以使用from
移动范围。它的行为很像
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;
}
#包括
#包括
#包括
#包括
int main()
{
std::vectorsharedv;
std::向量uniqueV;
独特的安置(标准::使独特(42));
std::move(uniqueV.begin()、uniqueV.end()、std::back_inserter(sharedV));
返回0;
}
要添加到,std::vector有一个范围成员函数。仅仅将迭代器传递给
unique_ptr
的向量是不起作用的,但是有一种方法可以将这些迭代器的解引用从左值转换为xvalues:及其相应的工厂函数:

这可能比使用
std::back\u inserter
更有效的原因是
insert()
预先知道结果大小,因此最多只需进行一次分配,然后实际插入不需要进行大小检查

写这篇文章太难了,我建议对这个名为
extend()
的函数使用基于范围的重载:


因此,最好使用std::shared\u ptr,而不是这些东西是否需要参与所有权?如果没有,您可以通过引用传递向量。@NathanOliver对于某些特定情况,我们希望共享这些指针的所有权。不要过分热心:)会建议[令人沮丧的]更详细但也更有效的
sharedV.insert(sharedV.end(),std::make\u move\u迭代器(uniqueV.begin()),std::make\u move\u迭代器(uniqueV.end())
@Barry我不知道
std::make\u move\u迭代器
。非常有趣。如果在我的答案后面附加这个解决方案,我会感到不舒服,我觉得它应该是一个明确的答案。好吧,如果你坚持:)我发现,首先调整目标向量的大小,然后只调整移动算法(或for循环)更具可读性。在这种情况下,这应该同样有效。实现者可以使用
back\u inserter
进行同样的优化,对吗?@gmannickhow?通过添加每个算法的重载来获取输出迭代器?巴里:我想如果迭代器是随机访问迭代器,而输出迭代器是back\u插入器,那么实现可以额外检查back\u插入器中的容器是否可以
reserve
,如果可以,调用
reserve(std::distance(begin,end))
。然后像平常一样继续下去。这一切在编译时都应该是可行的。尽管仔细想想,
move
的允许操作可能会完全禁止这种w.r.t异常。无需改变容量可能是不可取的。
sharedV.insert(sharedV.end(),
    std::make_move_iterator(uniqueV.begin()),
    std::make_move_iterator(uniqueV.end()));
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)));
    }
}
extend(sharedV, std::move(uniqueV));