Как создать + заполнить контейнер на месте? - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь создать массив классов, которые нельзя скопировать или переместить. Поэтому мне нужно создать объекты на месте, и я не могу понять, как это сделать:

#include <vector>

struct Foo {
  Foo(int) { }
  Foo(const Foo &) = delete;
  Foo & operator =(const Foo &) = delete;
  Foo(Foo &&) = delete;
  Foo & operator =(Foo &&) = delete;
};

struct Bla {
  Bla(const std::vector<int> & args) {
    for (auto i : args) {
      foo.emplace_back(i);
    }
  }
  std::vector<Foo> foo;
};

Компилятор жалуется на удаленный конструктор перемещения, потому что не гарантируется, что все объекты построены на месте и никогда не перемещаются. Мне не нужно использовать std::vector в качестве контейнера, поэтому не стесняйтесь предлагать что-то еще.

Ответы [ 3 ]

0 голосов
/ 11 января 2019

Вы можете использовать std::vector s конструктор пары итераторов для создания объектов типа

Bla(const std::vector<int> & args) 
    : foo(args.begin(), args.end())
{}

Если у вас есть дополнительные параметры, которые необходимо включить в конструкцию, вы можете переключиться на любой из контейнеров на основе узлов, например std::list

struct Bla {
  Bla(const std::vector<int> & args) {
    for (auto i : args) {
      foo.emplace_back(i, some_other_argument);
    }
  }
  std::list<Foo> foo;
};
0 голосов
/ 11 января 2019

Для наиболее общего случая не существует ли способа составить список инициализаторов из векторных аргументов и лямбды?

Альтернативный способ создания контейнера STL Foo, который не может быть скопирован или перемещен, содержит std::unique_ptr<Foo>, который является подвижным. Например, в более общем случае, если первый и второй аргументы ctor Foo равны int и double соответственно, тогда для вас будет работать следующий Bla:

DEMO

#include <tuple>
#include <vector>
#include <memory>

struct Bla
{
    Bla(const std::vector<std::tuple<int, double>>& args)
    {
        foo.reserve(args.size());

        for (const auto& i : args) {
            foo.push_back(
                std::make_unique<Foo>(std::get<0>(i), std::get<1>(i)));
        }
    }

    std::vector<std::unique_ptr<Foo>> foo;
};
0 голосов
/ 11 января 2019

Одним из способов является использование конструктора диапазона. Он не перераспределяет вектор при передаче итераторов произвольного доступа:

Bla(const std::vector<int> & args) 
    : foo(args.begin(), args.end())
{}
...