2017-08-24 228 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

相關問題