Как проще всего инициализировать std :: vector жестко закодированными элементами?

518

Я могу создать массив и инициализировать его следующим образом:

int a[] = {10, 20, 30};

Как создать std::vector и инициализировать его так же элегантно?

Лучший способ узнать:

std::vector<int> ints;

ints.push_back(10);
ints.push_back(20);
ints.push_back(30);

Есть ли лучший способ?

  • 1
    если вы не собираетесь изменять размер целых чисел после инициализации, рассмотрите возможность использования массива tr1.
  • 0
    @zr, вы меня любопытно ... если бы мне нужен фиксированный размер, не могли бы я использовать сами старые массивы? Глядя на массив tr1 прямо сейчас ...
Показать ещё 4 комментария
Теги:
initialization
vector

25 ответов

510
Лучший ответ

Один из методов заключается в использовании массива для инициализации вектора

static const int arr[] = {16,2,77,29};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
  • 7
    @Agnel Он будет отлично работать без static и const , однако они оба делают его более понятным относительно того, как его следует использовать, и позволяют компилятору вносить дополнительные оптимизации.
  • 61
    Я не отрицал это, но я был искушаем. Главным образом потому, что это практически ничего не спасает от использования инициализированного массива. Однако это вина С ++, а не ваша.
Показать ещё 9 комментариев
505

Если ваш компилятор поддерживает С++ 11, вы можете просто сделать:

std::vector<int> v = {1, 2, 3, 4};

Это доступно в GCC начиная с версии 4.4. К сожалению, VС++ 2010, похоже, отстает в этом отношении.

В качестве альтернативы библиотека Boost.Assign использует макрос магии, чтобы разрешить следующее:

#include <boost/assign/list_of.hpp>
...
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);

Или:

#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
...
std::vector<int> v;
v += 1, 2, 3, 4;

Но имейте в виду, что у этого есть некоторые накладные расходы (в основном, list_of строит a std::deque под капотом), поэтому для высокопроизводительного кода вам лучше делать то, что говорит Якоби.

  • 0
    Так как векторы самоизмеримы, можно ли инициализировать их как пустые? Как и в конструкторе: this->vect = {}; ?
  • 3
    @Azurespot Вы можете просто инициализировать его, и он будет пустым: std::vector<T> vector;
Показать ещё 1 комментарий
68

В С++ 0x вы сможете сделать это так же, как и с массивом, но не в текущем стандарте.

С поддержкой только языка вы можете использовать:

int tmp[] = { 10, 20, 30 };
std::vector<int> v( tmp, tmp+3 ); // use some utility to avoid hardcoding the size here

Если вы можете добавить другие библиотеки, вы можете попробовать boost:: assign:

vector<int> v = list_of(10)(20)(30);

Чтобы избежать жесткого кодирования размера массива:

// option 1, typesafe, not a compile time constant
template <typename T, std::size_t N>
inline std::size_t size_of_array( T (&)[N] ) {
   return N;
}
// option 2, not typesafe, compile time constant
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

// option 3, typesafe, compile time constant
template <typename T, std::size_t N>
char (&sizeof_array( T(&)[N] ))[N];    // declared, undefined
#define ARRAY_SIZE(x) sizeof(sizeof_array(x))
  • 0
    Конечно, я не отрицал, но у меня все равно есть вопрос: когда размер массива не является постоянной времени компиляции? Т.е. в каких случаях вы бы использовали первое решение во втором фрагменте, а не третье?
  • 0
    + голосуй с моей стороны. В C ++ 0x вы можете создать constexpr из варианта 1. Но опять же, это больше не будет использоваться: S
Показать ещё 6 комментариев
49

В С++ 11:

#include <vector>
using std::vector;
...
vector<int> vec1 { 10, 20, 30 };
// or
vector<int> vec2 = { 10, 20, 30 };

Использование boost list_of:

#include <vector>
#include <boost/assign/list_of.hpp>
using std::vector;
...
vector<int> vec = boost::assign::list_of(10)(20)(30);

Использование функции boost:

#include <vector>
#include <boost/assign/std/vector.hpp>
using std::vector;
...
vector<int> vec;
vec += 10, 20, 30;

Обычный STL:

#include <vector>
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );

Обычный STL с общими макросами:

#include <vector>
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])
#define ARRAY_END(ar) (ar + ARRAY_SIZE(ar))
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, ARRAY_END(arr));

Обычный STL с вектором инициализатора:

#include <vector>
#define INIT_FROM_ARRAY(ar) (ar, ar + sizeof(ar) / sizeof(ar[0])
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec INIT_FROM_ARRAY(arr);
  • 1
    C ++ 11 также поддерживает std::begin и std::end для массива, поэтому вектор также можно инициализировать как static const int arr[] = {10,20,30}; vector<int> vec(begin(arr), end(arr)); ,
48

Просто подумал, что я брошу свои $0,02. Я склонен объявлять это:

template< typename T, size_t N >
std::vector<T> makeVector( const T (&data)[N] )
{
    return std::vector<T>(data, data+N);
}

в заголовке утилиты где-то, а затем все, что требуется:

const double values[] = { 2.0, 1.0, 42.0, -7 };
std::vector<double> array = makeVector(values);

Но я не могу дождаться С++ 0x. Я застрял, потому что мой код также должен компилироваться в Visual Studio. Boo.

  • 1
    Эту технику также можно использовать для перегрузки функции для приема массива с типизированным размером.
  • 4
    Можете ли вы объяснить часть const T (&data)[N] ? Как определяется размер массива в вашем вызове makeVector(values) ?
31

Ради бога, используйте современный C++ [11,14,17,...] способ:

std::vector<int> vec = {10,20,30};

Старый способ циклы над массивом переменной длины или с использованием sizeof() действительно ужасен на глазах и совершенно ненужен с точки зрения умственных накладных расходов. Тьфу.

  • 2
    Справедливости ради, изначально это был вопрос C ++ 03, но я надеюсь, что люди / компании примут новые стандарты. C ++ по-прежнему нуждается в реализации массива переменной длины (VLA) в стандартной библиотеке, аналогичной доступной в Eigen и Boost.
  • 0
    К сожалению, этот подход проблематичен в некоторых случаях, например, open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467 . Тьфу.
30

До С++ 11:

Метод 1 = >

vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
vector<int>v;

Метод 2 = >

 v.push_back(SomeValue);

С++ 11 также ниже

vector<int>v = {1, 3, 5, 7};
26

Начиная с:

int a[] = {10, 20, 30}; //i'm assuming a is just a placeholder

Если у вас нет компилятора С++ 11, и вы не хотите использовать boost:

const int a[] = {10, 20, 30};
const std::vector<int> ints(a,a+sizeof(a)/sizeof(int)); //make it const if you can

Если у вас нет компилятора С++ 11 и вы можете использовать boost:

#include <boost/assign.hpp>
const std::vector<int> ints = boost::assign::list_of(10)(20)(30);

Если у вас есть компилятор С++ 11:

const std::vector<int> ints = {10,20,30};
20

Самый простой способ сделать это:

vector<int> ints = {10, 20, 30};
  • 4
    Какой компилятор? Вы используете C ++ 11 здесь?
  • 0
    g ++ 4.6.3 с -std = c ++ 0x.
17

Для векторной инициализации -

vector<int> v = {10,20,30}

может быть выполнено, если у вас есть компилятор С++ 11.

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

int array[] = {10,20,30}
for(int i=0; i<sizeof(array); i++)
     v.push_back(array[i]);

Кроме того, существуют различные способы, описанные выше, с использованием некоторого кода. На мой взгляд, эти способы легко запомнить и быстро написать.

12

Если ваш компилятор поддерживает Variadic macros (что верно для большинства современных компиляторов), вы можете использовать следующий макрос, чтобы преобразовать векторную инициализацию в однострочный:

#define INIT_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))

С помощью этого макроса вы можете определить инициализированный вектор с таким кодом:

INIT_VECTOR(int, my_vector, {1, 2, 3, 4});

Это создаст новый вектор int с именем my_vector с элементами 1, 2, 3, 4.

10

Если вы не хотите использовать boost, но хотите использовать синтаксис, например

std::vector<int> v;
v+=1,2,3,4,5;

просто включите этот фрагмент кода

template <class T> class vector_inserter{
public:
    std::vector<T>& v;
    vector_inserter(std::vector<T>& v):v(v){}
    vector_inserter& operator,(const T& val){v.push_back(val);return *this;}
};
template <class T> vector_inserter<T> operator+=(std::vector<T>& v,const T& x){
    return vector_inserter<T>(v),x;
}
  • 1
    Я не смог понять, как использовать этот код, но он выглядит интересно.
  • 0
    Это как один из вышеупомянутых комментариев. Просто перегрузка + = и оператор запятой. Поставим скобки для ясности: ((((v+=1),2),3),4),5) Вот как это работает: во-первых, vector<T> += T возвращает vector_inserter, давайте назовем его vi который инкапсулирует исходный вектор, затем vi,T добавляют T к исходному вектору, который vi инкапсулирует и возвращает его самостоятельно, чтобы мы могли снова выполнить vi,T
Показать ещё 3 комментария
9

В С++ 11:

static const int a[] = {10, 20, 30};
vector<int> vec (begin(a), end(a));
  • 21
    Если вы уже используете C ++ 11, вы можете также пойти на прямой подход - vector<int> arr = {10, 20, 30}; ,
  • 0
    На самом деле у меня был входящий int [] (немного C lib) и я хотел вставить в вектор (C ++ lib). Этот ответ помог, остальные не сделали ;-)
9

Я создаю собственное решение с помощью va_arg. Это решение совместимо с C98.

#include <cstdarg>
#include <iostream>
#include <vector>

template <typename T>
std::vector<T> initVector (int len, ...)
{
  std::vector<T> v;
  va_list vl;
  va_start(vl, len);
  for (int i = 0; i < len; ++i)
    v.push_back(va_arg(vl, T));
  va_end(vl);
  return v;
}

int main ()
{
  std::vector<int> v = initVector<int> (7,702,422,631,834,892,104,772);
  for (std::vector<int>::const_iterator it = v.begin() ; it != v.end(); ++it)
    std::cout << *it << std::endl;
  return 0;
}

демонстрация

9

вы можете сделать это, используя boost:: assign.

vector<int> values;  
values += 1,2,3,4,5,6,7,8,9;

подробнее здесь

  • 16
    Я не видел худшего случая злоупотребления перегрузкой оператора в течение долгого времени. Добавляет ли += туда 1,2,3,4 .. до конца значений или добавляет 1 к 1-му элементу, 2 к 2-му элементу, 3 к 3-му элементу (так как синтаксис должен выглядеть так: MATLAB-подобные языки)
8

В более позднем дублированном вопросе этот ответ Виктор Сер. Для меня это компактно, визуально привлекательно (похоже, что вы "перетаскиваете" значения в), не требует С++ 11 или стороннего модуля и избегает использования дополнительной (записанной) переменной. Ниже приведен пример использования нескольких изменений. Я могу переключиться на расширение функции вектора и/или va_arg в будущем.


// Based on answer by "Viktor Sehr" on Stack Overflow
// /questions/15901/how-to-initialize-a-vector-in-c/116266#116266
//
template <typename T>
class mkvec {
public:
    typedef mkvec<T> my_type;
    my_type& operator<< (const T& val) {
        data_.push_back(val);
        return *this;
    }
    my_type& operator<< (const std::vector<T>& inVector) {
        this->data_.reserve(this->data_.size() + inVector.size());
        this->data_.insert(this->data_.end(), inVector.begin(), inVector.end());
        return *this;
    }
    operator std::vector<T>() const {
        return data_;
    }
private:
    std::vector<T> data_;
};

std::vector<int32_t>    vec1;
std::vector<int32_t>    vec2;

vec1 = mkvec<int32_t>() << 5 << 8 << 19 << 79;  
// vec1 = (5,8,19,79)
vec2 = mkvec<int32_t>() << 1 << 2 << 3 << vec1 << 10 << 11 << 12;  
// vec2 = (1,2,3,5,8,19,79,10,11,12)
4

Ниже приведены методы, которые можно использовать для инициализации вектора в С++.

  • int arr[] = {1, 3, 5, 6}; vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));

  • vector<int>v; v.push_back(1); v.push_back(2); v.push_back(3); и т.д.

  • vector<int>v = {1, 3, 5, 7};

Третий разрешен только в С++ 11 и далее.

3

Если массив:

int arr[] = {1, 2, 3};
int len = (sizeof(arr)/sizeof(arr[0])); // finding length of array
vector < int > v;
std:: v.assign(arr, arr+len); // assigning elements from array to vector 
3
// Before C++11
// I used following methods:

// 1.
int A[] = {10, 20, 30};                              // original array A

unsigned sizeOfA = sizeof(A)/sizeof(A[0]);           // calculate the number of elements

                                                     // declare vector vArrayA,
std::vector<int> vArrayA(sizeOfA);                   // make room for all
                                                     // array A integers
                                                     // and initialize them to 0 

for(unsigned i=0; i<sizeOfA; i++)
    vArrayA[i] = A[i];                               // initialize vector vArrayA


//2.
int B[] = {40, 50, 60, 70};                          // original array B

std::vector<int> vArrayB;                            // declare vector vArrayB
for (unsigned i=0; i<sizeof(B)/sizeof(B[0]); i++)
    vArrayB.push_back(B[i]);                         // initialize vArrayB

//3.
int C[] = {1, 2, 3, 4};                              // original array C

std::vector<int> vArrayC;                            // create an empty vector vArrayC
vArrayC.resize(sizeof(C)/sizeof(C[0]));              // enlarging the number of 
                                                     // contained elements
for (unsigned i=0; i<sizeof(C)/sizeof(C[0]); i++)
     vArrayC.at(i) = C[i];                           // initialize vArrayC


// A Note:
// Above methods will work well for complex arrays
// with structures as its elements.
3

Здесь есть много хороших ответов, но, поскольку я самостоятельно добрался до своего имени, прежде чем прочесть это, я решил, что все равно подброшу сюда...

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

Создайте структуру или класс как контейнер для вашей коллекции объектов. Определите функцию перегрузки оператора для <

class MyObject;

struct MyObjectList
{
    std::list<MyObject> objects;
    MyObjectList& operator<<( const MyObject o )
    { 
        objects.push_back( o );
        return *this; 
    }
};

Вы можете создавать функции, которые принимают вашу структуру как параметр, например:

someFunc( MyObjectList &objects );

Затем вы можете вызвать эту функцию, например:

someFunc( MyObjectList() << MyObject(1) <<  MyObject(2) <<  MyObject(3) );

Таким образом, вы можете создавать и передавать набор объектов с динамическим размером в функцию в одной чистой строке!

3
typedef std::vector<int> arr;

arr a {10, 20, 30};       // This would be how you initialize while defining

Чтобы скомпилировать использование:

clang++ -std=c++11 -stdlib=libc++  <filename.cpp>
  • 0
    Состояния вопроса C ++ 03 (не 11)
  • 1
    Я думаю, что это не указывает 03, когда я ответил на это. Хотя не помню точно. Тем не менее, это все еще полезный ответ для тех, кто ищет быстрое решение.
3

Если вы хотите что-то в том же общем порядке, что и Boost:: assign, не создавая зависимости от Boost, следующее, по крайней мере, смутно похожее:

template<class T>
class make_vector {
    std::vector<T> data;
public:
    make_vector(T const &val) { 
        data.push_back(val);
    }

    make_vector<T> &operator,(T const &t) {
        data.push_back(t);
        return *this;
    }

    operator std::vector<T>() { return data; }
};

template<class T> 
make_vector<T> makeVect(T const &t) { 
    return make_vector<T>(t);
}

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

std::vector<int> x = (makeVect(1), 2, 3, 4);
1

В. Stroustrup описывает хороший способ цепных операций в 16.2.10 Selfreference на стр. 464 в выпуске С++ 11 Prog. Lang. где функция возвращает ссылку, здесь изменена на вектор. Таким образом, вы можете цепью, как v.pb(1).pb(2).pb(3);, но может быть слишком большой работой для таких небольших выигрышей.

#include <iostream>
#include <vector>

template<typename T>
class chain
{
private:
    std::vector<T> _v;
public:
    chain& pb(T a) {
        _v.push_back(a);
        return *this;
    };
    std::vector<T> get() { return _v; };
};

using namespace std;

int main(int argc, char const *argv[])
{
    chain<int> v{};

    v.pb(1).pb(2).pb(3);

    for (auto& i : v.get()) {
        cout << i << endl;
    }

    return 0;
}

1
2
3

  • 0
    Библиотека armadillo делает это для инициализации матрицы, но использует оператор << вместо именованной функции: arma.sourceforge.net/docs.html#element_initialisation
1

Связанный, вы можете использовать следующее, если хотите, чтобы вектор был полностью готов к быстрому оператору (например, сразу же перешел к другой функции):

#define VECTOR(first,...) \
   ([](){ \
   static const decltype(first) arr[] = { first,__VA_ARGS__ }; \
   std::vector<decltype(first)> ret(arr, arr + sizeof(arr) / sizeof(*arr)); \
   return ret;})()

примерная функция

template<typename T>
void test(std::vector<T>& values)
{
    for(T value : values)
        std::cout<<value<<std::endl;
}

Пример использования

test(VECTOR(1.2f,2,3,4,5,6));

но будьте осторожны с объявлением, убедитесь, что первое значение явно то, что вы хотите.

1

"Как создать вектор STL и инициализировать его, как указано выше? Каков наилучший способ сделать это с минимальным усилием набора текста?"

Самый простой способ инициализировать вектор, как вы инициализировали свой встроенный массив, - это использовать список инициализаторов, который был введен в С++ 11.

// Initializing a vector that holds 2 elements of type int.
Initializing:
std::vector<int> ivec = {10, 20};


// The push_back function is more of a form of assignment with the exception of course
//that it doesn't obliterate the value of the object it being called on.
Assigning
ivec.push_back(30);

ivec - это 3 элемента по размеру после выполнения команды Assigning (labeled statement).

  • 0
    В аналогичных строках я пытаюсь инициализировать карту, std :: map <int, bool> catinfo = {{1, false}}; Но затем получите эту ошибку: в C ++ 98 'catinfo' должна быть инициализирована конструктором, а не '{...}'

Ещё вопросы

Сообщество Overcoder
Наверх
Меню