移动std :: vector <std :: unique_ptr <t>&gt;到std :: vector <std :: shared_ptr <t>&gt;

时间:2017-08-24 14:29:23

标签: c++ c++11 stl c++14

有时我们有一个工厂生成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集合做这样的事情吗?

2 个答案:

答案 0 :(得分:8)

您可以使用<algorithm>中的std::move来移动范围。它的行为与std::copy非常相似,但相反。以下示例将所有unique_ptruniqueV移至sharedVuniqueV的元素在示例末尾都是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));