Как инициализировать std :: vector из массива в стиле C? - PullRequest
148 голосов
/ 12 марта 2010

Какой самый дешевый способ инициализации std::vector из массива в стиле C?

Пример: в следующем классе у меня есть vector, но из-за внешних ограничений данные будут переданы в виде массива в стиле C:

class Foo {
  std::vector<double> w_;
public:
  void set_data(double* w, int len){
   // how to cheaply initialize the std::vector?
}

Очевидно, что я могу позвонить w_.resize(), а затем перебрать элементы или вызвать std::copy(). Есть ли лучшие методы?

Ответы [ 5 ]

206 голосов
/ 12 марта 2010

Не забывайте, что вы можете рассматривать указатели как итераторы:

w_.assign(w, w + len);
37 голосов
/ 12 марта 2010

Вы используете слово initialize, поэтому неясно, является ли это однократным назначением или может происходить несколько раз.

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

Foo::Foo(double* w, int len) : w_(w, w + len) { }

В противном случае используйте assign, как предлагалось ранее:

void set_data(double* w, int len)
{
    w_.assign(w, w + len);
}
11 голосов
/ 04 июня 2015

Ну, Павел был близок, но есть даже более простое и элегантное решение для инициализации последовательного контейнера из массива стиля c.

В вашем случае:

w_ (array, std::end(array))
  • массив получит указатель на начало массива (не уловил его имя),
  • std :: end (array) приведет нас к итератору до конца массива.
9 голосов
/ 17 октября 2013

Вы можете «узнать» размер массива автоматически:

template<typename T, size_t N>
void set_data(const T (&w)[N]){
    w_.assign(w, w+N);
}

Надеюсь, вы можете изменить интерфейс на set_data, как указано выше. Он по-прежнему принимает массив в стиле C в качестве первого аргумента. Это просто происходит, чтобы взять его по ссылке.


Как это работает

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

Вот более общее решение:

template<typename T, size_t N>
void copy_from_array(vector<T> &target_vector, const T (&source_array)[N]) {
    target_vector.assign(source_array, source_array+N);
}

Это работает, потому что массив передается как ссылка на массив. В C / C ++ вы не можете передать массив как функцию, вместо этого он распадется на указатель, и вы потеряете размер. Но в C ++ вы можете передать ссылку на массив.

Передача массива по ссылке требует, чтобы типы точно совпадали. Размер массива является частью его типа. Это означает, что мы можем использовать параметр шаблона N, чтобы узнать размер для нас.

Может быть, еще проще иметь эту функцию, которая возвращает вектор. При наличии соответствующих оптимизаций компилятора это должно быть быстрее, чем кажется.

template<typename T, size_t N>
vector<T> convert_array_to_vector(const T (&source_array)[N]) {
    return vector<T>(source_array, source_array+N);
}
0 голосов
/ 12 марта 2010

std::vector<double>::assign - это путь, потому что это маленький код . Но как это работает на самом деле? Разве это не изменить размер, а затем скопировать? В MS реализации STL я использую это именно так.

Боюсь, что нет более быстрого способа реализовать (пере) инициализацию std::vector

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...