2016-01-15 3 views
4

У меня есть класс Foo с переменной-членом типа std::vector<std::unique_ptr<Bar>>, который я бы хотел заполнить в списке инициализации конструктора этого класса. Это возможно?Можно ли создать std :: vector <std :: unique_ptr <Bar>> с помощью конструктора заливки?

Я надеялся, что с помощью заливки конструктор вектора будет возможно, что-то вроде этого

Foo::Foo(int n): 
    vector<unique_ptr<Bar>> (n, unique_ptr<Bar> (new Bar)) 
{} 

, но я думаю, что это требует копирования конструктор std::unique_ptr, который удален (как это должно быть) (unique_ptr(const unique_ptr&) = delete) ,

Есть ли лучший способ сделать это?

+1

Вы правы в что ваша попытка не будет работать, потому что вы вызываете только «новый бар» один раз, тогда как для вектора уникальных указателей вам нужно называть «новый бар» один раз для каждого элемента. Я думаю, вам лучше всего использовать цикл с 'emplace_back'. –

+0

В качестве альтернативы вы можете заполнить конструкцию пустым 'unique_ptr', а затем цикл через вызов' reset (new Bar) 'на каждом из них. –

+0

Пока C++ не получит повторяющиеся сопрограммы, я думаю, что ваш лучший выбор - это цикл. – zneak

ответ

4

Поскольку это невозможно для копирования, переместите его!

Решение с жестко закодированных объектов:

#include <memory> 
#include <vector> 
#include <iterator> 
class Bar{}; 
class Foo{ 
    public: 
    Foo():bars(get_bars()) {} 
    std::vector<std::unique_ptr<Bar>> bars; 

    private: 
    std::vector<std::unique_ptr<Bar>> get_bars(){ 
     std::unique_ptr<Bar> inilizer_list_temp[]={std::make_unique<Bar>(),std::make_unique<Bar>(),std::make_unique<Bar>()}; 
     return std::vector<std::unique_ptr<Bar>>{std::make_move_iterator(std::begin(inilizer_list_temp)),std::make_move_iterator(std::end(inilizer_list_temp))}; 
    } 
}; 
int main() 
{ 
    Foo foo; 
} 

Live Demo

Решение с динамическим числом объектов:

#include <memory> 
#include <vector> 
#include <iterator> 
#include <iostream> 
class Bar{ 
    public: 
    int a=5; 
    }; 
class Foo{ 
    public: 
    Foo():bars(get_bars(10)) {} 
    std::vector<std::unique_ptr<Bar>> bars; 

    private: 
    std::vector<std::unique_ptr<Bar>> get_bars(int n){ 
     std::vector<std::unique_ptr<Bar>> inilizer_list_temp; 
     inilizer_list_temp.reserve(n); 
     for(size_t i=0;i<n;++i){ 
      inilizer_list_temp.emplace_back(std::make_unique<Bar>()); 
     } 
     return inilizer_list_temp; 
    } 
}; 
int main() 
{ 
Foo foo; 
for(auto const& item:foo.bars){ 
    std::cout << item->a; 
} 
} 

Live Demo

и посмотрим подробнее Can I list-initialize a vector of move-only type?

EDIT:

Для C++ 11 пользователей, не станд :: make_uniuqe:

template<typename T, typename ...Args> 
std::unique_ptr<T> make_unique(Args&& ...args) 
{ 
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); 
} 

Source

+0

Мне кажется, что вопрос заключается в том, чтобы избежать цикла и не вводить логику создания unique_pointer для каждого экземпляра. В вашем ответе предлагается hardcoding набор уникальных указателей и переход от него, что в корне совпадает с заполнением вектора вручную ... – zneak

+0

Хорошо работает с 2, примерно 2000? –

+0

Спасибо .. Отредактировано –

Смежные вопросы