2017-08-24 128 views
3

有时会出现这样的情况:我们有一个工厂生成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); 

那么,有没有简单的方法做这样的事情性病收藏?

+0

*所以这将是可取的使用std :: shared_ptr代替*这些事情需要参与所有权吗?如果没有,你可以通过引用传递向量。 – NathanOliver

+0

@NathanOliver对于某些我们希望共享这些指针所有权的特定情况,我们期望这样做。不要过分:) – Amadeusz

回答

8

您可以使用<algorithm>中的std::move来移动范围。它的行为与std::copy很相似,但会改为移动。以下示例将将所有unique_ptruniqueV移至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; 
} 
+3

建议[令人沮丧]更详细,但也更有效的'sharedV.insert(sharedV.end(),std :: make_move_iterator(uniqueV.begin()),std :: make_move_iterator(uniqueV。 end()))' – Barry

+0

@Barry我不知道'std :: make_move_iterator'。很有意思。我会不舒服地将这个解决方案附加到我的答案上,我觉得它应该是一个明确的答案。 –

+0

好吧,如果你坚持:) – Barry

5

要添加上的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)); 
+0

我发现它更具可读性,首先调整目标矢量的大小,然后只是移动算法(或for循环)。在这种情况下,这应该是同样有效的。 – MikeMB

+0

执行者可以使用'back_inserter'进行相同的优化,对吧? – GManNickG

+0

@GManNickG如何?通过添加输出迭代器的每个算法的重载?我猜可能,但看起来并不特别实际。 – Barry

相关问题