2016-09-13 3 views
6

でベクター中にいくつかのunique_ptrsを挿入します。メンバー関数std::vector::insert(iterator position, size_type n, const value_type& val)がありますが、残念ながら、unique_ptrのコピーにはこのオーバーロードを使用できません。はどのようにベクトルを持って一度

私はthis questionを読んでいますが、既に他のベクターに存在するunique_ptrを挿入するためのものです。私は新しいものを作りたい。

私はベクトルの先頭に3つの新しい項目を挿入するために、たとえば、ループでそれを行うことができます実現:これを行うにはクリーンな方法があります場合、私は思ったんだけどしかし

for (int n = 0; n != 3; ++n) 
    vec.insert(vec.begin(), std::make_unique<int>(0)); 

をし、おそらくは新しいメモリを前もって割り当てるものです。

明示的に編集する:ベクトルに追加する項目の数は完全に任意です - 私は3つのコードを記述していますが、コンパイル時には必ずしも値でなくてもかまいません。

+6

を避けるためにgenerate_nを使用することができます'std :: make_unique()'を呼び出すか、ポインタの別の配列/コンテナから移動します。それ以外の場合は、デザインを再考してください。例えば、3つの要素を持つ単一の 'std :: vector 'を持つことができます。あるいは、3要素配列を保持する 'std :: unique_ptr 'と、その配列への生ポインタを含む別々の 'std :: vector 'です。 –

+0

...または 'のstd :: generate_n( のstd ::サーター(VEC、vec.begin())、 3、 のstd ::バインド(のstd :: make_unique 、0) );'しかし、私はwouldnそれを清潔にしてはいけません。 – jrok

答えて

1

あなたは、ベクターに入れたいどのように多くのポインタコンパイル時にわかっている場合は、次のいずれかのよう機能を使用することができます。

#include<vector> 
#include<memory> 
#include<cstddef> 

template<std::size_t... I> 
constexpr auto gen(std::index_sequence<I...>) { 
    std::vector<std::unique_ptr<int>> vec; 
    int arr[] = { (vec.push_back(std::make_unique<int>(0)), I)... }; 
    (void)arr; 
    return vec; 
} 

template<std::size_t N> 
constexpr auto create() { 
    return gen(std::make_index_sequence<N>{}); 
} 

int main() { 
    auto vec = create<3>(); 
} 
+0

交互に、arrをすべて避けてください: '(vec.push_back(std :: make_unique (0 * I))、...);' – bolov

1

ここに割り当てられているメモリの2種類があります。 unique_ptrのためにvectorに割り当てられたメモリがあります(それほど多くはありませんが、unique_ptrあたりのポインタです)。そして、unique_ptrによって管理されているオブジェクトの動的に割り当てられたメモリ。

を割り当てることはできませんそれぞれのオブジェクト内のオブジェクトに動的に割り当てられたメモリを個別に割り当てる必要があります。

しかし、あなたが原因複数のベクトル用のメモリの再割り当てを回避したい場合はinsertあなたが最初に準備を行うことができます呼び出します。

vec.reserve(vec.size() + n); 

私はそれはしかし3ほどの小さなnのための任意の影響を与えることはないだろう。

さらに多くの問題点は、insertごとに、ベクトルがvectorのすべての内容を挿入ポイントの後に1つ移動しなければならないことです。移動するunique_ptrは安いですが、それは追加することができます。

これは確かにクリーナーではありませんが、std::move_backwardを使用すると一度自分を動かすことができます。、サイズ必要にベクトルのサイズを変更するに沿って、すべての要素を移動してから、挿入したい要素で移動-割り当てるunique_ptr

auto prev_size = vec.size(); 
vec.resize(prev_size + 3); 
auto prev_end = vec.begin() + prev_size; 
std::move_backward(vec.begin(), prev_end, vec.end()); 
for (int n = 0; n != 3; ++n) 
    vec[n] = std::make_unique<int>(0); 

別の、おそらくクリーナー、同じことを達成する方法を作成することです独自のカスタムinsertstd::vector::insert(const_iterator position, InputIterator first, InputIterator last);過負荷で使用するために、前方反復子:

template<typename T> 
struct UniquePtrInserter : std::iterator< 
          std::forward_iterator_tag, 
          std::unique_ptr<T>, 
          std::ptrdiff_t, 
          const std::unique_ptr<T>*, 
          std::unique_ptr<T>>{ 
    int n_; 
public: 
    explicit UniquePtrInserter<T>(int n = 0) : n_(n) {} 
    UniquePtrInserter<T>& operator++() {n_++; return *this;} 
    bool operator==(UniquePtrInserter<T> other) const {return n_ == other.n_;} 
    bool operator!=(UniquePtrInserter<T> other) const {return !(*this == other);} 
    std::unique_ptr<T> operator*() const {return std::make_unique<T>(); } 
}; 

vec.insert(vec.begin(), UniquePtrInserter<int>(0), UniquePtrInserter<int>(3)); 
0

これを行うためのクリーンな方法は、例えば、要素を移動する移動イテレータを使用することです:

#include <iostream> 
#include <vector> 
#include <memory> 
#include <iterator> 

using T = std::unique_ptr<int>; 

void print_vec(const std::vector<T>& vec) 
{ 
    for (auto& x: vec) { 
     std::cout << ' ' << *x; 
    } 
    std::cout << '\n'; 
} 

template <typename V, typename ...X> 
void emplace(V& v, typename V::const_iterator i, X&&... x) { 
    T a[] = { std::forward<X>(x)... }; 
    v.insert(i, std::make_move_iterator(std::begin(a)), std::make_move_iterator(std::end(a))); 
} 

int main() 
{ 
    std::vector<T> vec; 
    emplace(vec, vec.begin(), std::make_unique<int>(601), std::make_unique<int>(602), std::make_unique<int>(603)); 
    print_vec(vec);  
    emplace(vec, std::next(vec.begin()), std::make_unique<int>(501), std::make_unique<int>(502), std::make_unique<int>(503)); 
    print_vec(vec); 

} 

私はシンプルなラッパー関数を提供しました。この関数は、(可変引数のシーケンスとして)シーケンスをとり、move_iteratorを使ってベクトルに挿入します。

ただし、move_iteratorを使用して、移動演算子をサポートする任意のコンテナから移動することができます。

0

あなたは、各 `のstd :: unique_ptr`に別々の` int`を割り当てる必要があるので、ループを使用せずにこれを行うにはクリーンな方法がない生のループ

std::vector<std::unique_ptr<int>> vec; 
generate_n(back_inserter(vec), 3, []() { return make_unique<int>(); }); 
関連する問題