Подтвердить что ты не робот

С++, скопировать в вектор

Мне нужно скопировать std::set в std::vector:

std::set <double> input;
input.insert(5);
input.insert(6);

std::vector <double> output;
std::copy(input.begin(), input.end(), output.begin()); //Error: Vector iterator not dereferencable

Где проблема?

4b9b3361

Ответ 1

Вам нужно использовать back_inserter:

std::copy(input.begin(), input.end(), std::back_inserter(output));

std::copy не добавляет элементы в контейнер, в который вы вставляете: он не может; он имеет только итератор в контейнер. Из-за этого, если вы передаете выходный итератор непосредственно на std::copy, вы должны убедиться, что он указывает диапазон, который по крайней мере достаточно велик, чтобы удерживать диапазон ввода.

std::back_inserter создает выходной итератор, который вызывает push_back в контейнере для каждого элемента, поэтому каждый элемент вставляется в контейнер. В качестве альтернативы вы могли бы создать достаточное количество элементов в std::vector для хранения скопированного диапазона:

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

Или вы можете использовать конструктор диапазона std::vector:

std::vector<double> output(input.begin(), input.end()); 

Ответ 2

Просто используйте конструктор для вектора, который принимает итераторы:

std::set<T> s;

//...

std::vector v( s.begin(), s.end() );

Предполагается, что вы просто хотите, чтобы содержимое s в v, и ничего не было в v перед копированием данных на него.

Ответ 3

здесь другая альтернатива, использующая vector::assign:

theVector.assign(theSet.begin(), theSet.end());

Ответ 4

Вы не зарезервировали достаточное пространство в своем векторном объекте для хранения содержимого вашего набора.

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

Ответ 5

std::copy не может использоваться для вставки в пустой контейнер. Для этого вам необходимо использовать insert_iterator следующим образом:

std::set<double> input;
input.insert(5);
input.insert(6);

std::vector<double> output;
std::copy(input.begin(), input.end(), inserter(output, output.begin())); 

Ответ 6

Я думаю, что самый эффективный способ - это предварительно выделить, а затем использовать элементы:

template <typename T>
std::vector<T> VectorFromSet(const std::set<T>& from)
{
    std::vector<T> to;
    to.reserve(from.size());

    for (auto const& value : from)
        to.emplace_back(value);

    return to;
}

Таким образом, мы будем вызывать конструктор копирования только для каждого элемента, а не сначала вызывать конструктор по умолчанию, а затем копировать оператор присваивания для других решений, перечисленных выше. Больше разъяснений ниже.

  1. back_inserter может использоваться, но он вызовет push_back() для вектора (https://en.cppreference.com/w/cpp/iterator/back_insert_iterator). emplace_back() более эффективен, потому что избегает создания временного при использовании push_back(). Это не проблема с тривиально сконструированными типами, но будет влиять на производительность для нетривиально сконструированных типов (например, std :: string).

  2. Нам нужно избегать создания вектора с аргументом размера, который приводит к созданию всех элементов по умолчанию (ни за что). Как, например, с решением с использованием std :: copy().

  3. И, наконец, метод vector :: assign() или конструктор, принимающий диапазон итераторов, не являются хорошими вариантами, потому что они будут вызывать std :: distance() (чтобы узнать количество элементов) на итераторах множества. Это приведет к нежелательной дополнительной итерации по всем элементам набора, поскольку набор представляет собой структуру данных Binary Search Tree и не реализует итераторы с произвольным доступом.

Надеюсь, это поможет.