Какой самый дешевый способ инициализации 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()
. Есть ли лучшие методы?
Ответы:
Не забывайте, что вы можете рассматривать указатели как итераторы:
источник
assign
безусловно, может использовать их для оптимизации; по крайней мере, в VC ++, это действительно так.v.end()
итератор, указывающий один конец за концом вектором в аналогичном случае). Если вы получите утверждение, то что-то не так в другом месте.Вы используете слово initialize, поэтому неясно, является ли это однократным назначением или может происходить несколько раз.
Если вам нужна только однократная инициализация, вы можете поместить ее в конструктор и использовать векторный конструктор двух итераторов:
В противном случае используйте команду assign, как предлагалось ранее:
источник
Вы можете «узнать» размер массива автоматически:
Надеюсь, вы можете изменить интерфейс на set_data, как указано выше. Он по-прежнему принимает массив в стиле C в качестве первого аргумента. Это просто происходит, чтобы взять его по ссылке.
Как это устроено
[Обновление: см. Здесь для более всестороннего обсуждения изучения размера]
Вот более общее решение:
Это работает, потому что массив передается как ссылка на массив. В C / C ++ вы не можете передать массив как функцию, вместо этого он распадется на указатель, и вы потеряете размер. Но в C ++ вы можете передать ссылку на массив.
Передача массива по ссылке требует, чтобы типы точно совпадали. Размер массива является частью его типа. Это означает, что мы можем использовать параметр шаблона N, чтобы узнать размер для нас.
Возможно, было бы еще проще иметь эту функцию, которая возвращает вектор. При соответствующей оптимизации компилятора это должно быть быстрее, чем кажется.
источник
return { begin(source_array), end(source_array) };
также возможноЧто ж, Павел был близок, но есть даже более простое и элегантное решение для инициализации последовательного контейнера из массива стиля ac.
В твоем случае:
источник
array
(который обычно означает, что вы копируете из глобального или локального (объявленного в текущей функции) массива). В случае с OP он получает указатель и длину, и, поскольку длина не зависит от длины, они не могут перейти к получению указателя на размерный массив или что-либо еще, поэтомуstd::end
не будут работать.vector
не перегружаетсяoperator()
, так что это не скомпилируется.std::end
вызов по указателю также бесполезен (вопрос состоит в том, чтобы назначить вектор из указателя и отдельной переменной длины). Это улучшило бы ваш ответ, чтобы показать больше контекста о том, что вы пытаетесь предложитьБыстрый общий ответ:
или конкретный вопрос:
на основании выше : не забывайте, что вы можете рассматривать указатели как итераторы
источник
std::vector<double>::assign
это путь, потому что это маленький код . Но как это работает на самом деле? Разве это не изменить размер, а затем скопировать? В MS реализации STL я использую это именно так.Боюсь, что нет более быстрого способа реализовать (пере) инициализацию вашей
std::vector
.источник