Qual è il modo più semplice per inizializzare un vettore std :: con elementi hardcoded?

Posso creare un array e inizializzarlo in questo modo:

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

Come posso creare un std::vector e inizializzarlo in modo altrettanto elegante?

Il modo migliore che conosco è:

 std::vector ints; ints.push_back(10); ints.push_back(20); ints.push_back(30); 

C’è un modo migliore?

Un metodo sarebbe utilizzare la matrice per inizializzare il vettore

 static const int arr[] = {16,2,77,29}; vector vec (arr, arr + sizeof(arr) / sizeof(arr[0]) ); 

Se il tuo compilatore supporta C ++ 11, puoi semplicemente fare:

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

Questo è disponibile in GCC dalla versione 4.4 . Sfortunatamente, VC ++ 2010 sembra essere in ritardo in questo senso.

In alternativa, la libreria Boost.Assign utilizza la magia non macro per consentire quanto segue:

 #include  ... std::vector v = boost::assign::list_of(1)(2)(3)(4); 

O:

 #include  using namespace boost::assign; ... std::vector v; v += 1, 2, 3, 4; 

Ma tieni a mente che questo ha un sovraccarico (in pratica, list_of costruisce un std::deque sotto il cofano) quindi per il codice critico delle prestazioni faresti meglio a fare come dice Yacoby.

In C ++ 0x sarete in grado di farlo nello stesso modo in cui avete fatto con un array, ma non nello standard corrente.

Con il solo supporto linguistico puoi usare:

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

Se puoi aggiungere altre librerie puoi provare boost :: assignment:

 vector v = list_of(10)(20)(30); 

Per evitare la codifica hard della dimensione di un array:

 // option 1, typesafe, not a compile time constant template  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  char (&sizeof_array( T(&)[N] ))[N]; // declared, undefined #define ARRAY_SIZE(x) sizeof(sizeof_array(x)) 

Ho pensato di buttarmi i $ 0.02. Tendo a dichiararlo:

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

in un’intestazione di utilità da qualche parte e quindi tutto ciò che è richiesto è:

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

Ma non posso aspettare per C ++ 0x. Sono bloccato perché il mio codice deve anche compilare in Visual Studio. Boo.

In C ++ 11:

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

Utilizzando boost list_of:

 #include  #include  using std::vector; ... vector vec = boost::assign::list_of(10)(20)(30); 

Utilizzando l’assegnazione di boost:

 #include  #include  using std::vector; ... vector vec; vec += 10, 20, 30; 

STL convenzionale:

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

STL convenzionale con macro generiche:

 #include  #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 vec (arr, ARRAY_END(arr)); 

STL convenzionale con una macro di inizializzatore vettoriale:

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

Prima del C ++ 11:

Metodo 1 =>

 vector v(arr, arr + sizeof(arr)/sizeof(arr[0])); vectorv; 

Metodo 2 =>

  v.push_back(SomeValue); 

È ansible anche C ++ 11 in seguito

 vectorv = {1, 3, 5, 7}; 

Iniziare con:

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

Se non hai un compilatore C ++ 11 e non vuoi usare boost:

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

Se non hai un compilatore C ++ 11 e puoi usare boost:

 #include  const std::vector ints = boost::assign::list_of(10)(20)(30); 

Se hai un compilatore C ++ 11:

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

Per l’amor di Dio, usa il moderno modo C ++ [11,14,17, …]:

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

Il vecchio modo di eseguire il ciclo su un array a lunghezza variabile o usare sizeof() è veramente terribile per gli occhi e completamente inutile in termini di overhead mentale. Che schifo.

Il modo più semplice per farlo è:

 vector ints = {10, 20, 30}; 

Per l’inizializzazione del vettore –

 vector v = {10,20,30} 

può essere fatto se hai il compilatore c ++ 11.

Altrimenti, è ansible avere una matrice di dati e quindi utilizzare un ciclo for.

 int array[] = {10,20,30} for(int i=0; i 

Oltre a questi, ci sono vari altri modi descritti sopra usando del codice. Secondo me, questi modi sono facili da ricordare e veloci da scrivere.

Se il compilatore supporta macro Variadic (che è vero per la maggior parte dei compilatori moderni), quindi è ansible utilizzare la seguente macro per trasformare l’inizializzazione del vettore in una riga singola:

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

Con questa macro, puoi definire un vettore inizializzato con un codice come questo:

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

Questo creerebbe un nuovo vettore di Ints denominato my_vector con gli elementi 1, 2, 3, 4.

Se non vuoi usare boost, ma vuoi goderti la syntax come

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

solo includere questo pezzo di codice

 template  class vector_inserter{ public: std::vector& v; vector_inserter(std::vector& v):v(v){} vector_inserter& operator,(const T& val){v.push_back(val);return *this;} }; template  vector_inserter operator+=(std::vector& v,const T& x){ return vector_inserter(v),x; } 

puoi farlo usando boost :: assign.

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

dettaglio qui

In C ++ 11:

 static const int a[] = {10, 20, 30}; vector vec (begin(a), end(a)); 

Costruisco la mia soluzione utilizzando va_arg . Questa soluzione è conforms a C98.

 #include  #include  #include  template  std::vector initVector (int len, ...) { std::vector 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 v = initVector (7,702,422,631,834,892,104,772); for (std::vector::const_iterator it = v.begin() ; it != v.end(); ++it) std::cout < < *it << std::endl; return 0; } 

dimostrazione

Una domanda duplicata più recente ha questa risposta di Viktor Sehr . Per me è compatto, visivamente acctriggersnte (sembra che tu stia “spingendo” i valori dentro), non richiede c ++ 11 o un modulo di terze parti, ed evita di usare una variabile extra (scritta). Di seguito è come lo sto usando con alcune modifiche. Potrei passare ad estendere la funzione di vettore e / o va_arg nel futuro intead.


 // Based on answer by "Viktor Sehr" on Stack Overflow // https://stackoverflow.com/a/8907356 // template  class mkvec { public: typedef mkvec my_type; my_type& operator< < (const T& val) { data_.push_back(val); return *this; } my_type& operator<< (const std::vector& inVector) { this->data_.reserve(this->data_.size() + inVector.size()); this->data_.insert(this->data_.end(), inVector.begin(), inVector.end()); return *this; } operator std::vector() const { return data_; } private: std::vector data_; }; std::vector vec1; std::vector vec2; vec1 = mkvec() < < 5 << 8 << 19 << 79; // vec1 = (5,8,19,79) vec2 = mkvec() < < 1 << 2 << 3 << vec1 << 10 << 11 << 12; // vec2 = (1,2,3,5,8,19,79,10,11,12) 

Di seguito i metodi possono essere utilizzati per inizializzare il vettore in c ++.

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

  2. vectorv; v.push_back(1); v.push_back(2); v.push_back(3); e così via

  3. vectorv = {1, 3, 5, 7};

Il terzo è consentito solo in C ++ 11 in poi.

Se vuoi qualcosa sullo stesso ordine generale di Boost :: assign senza creare una dipendenza da Boost, quanto segue è almeno vagamente simile:

 template class make_vector { std::vector data; public: make_vector(T const &val) { data.push_back(val); } make_vector &operator,(T const &t) { data.push_back(t); return *this; } operator std::vector() { return data; } }; template make_vector makeVect(T const &t) { return make_vector(t); } 

Mentre spero che la syntax per usarlo sia più pulito, non è ancora particolarmente terribile:

 std::vector x = (makeVect(1), 2, 3, 4); 
 typedef std::vector arr; arr a {10, 20, 30}; // This would be how you initialize while defining 

Per compilare l’uso:

 clang++ -std=c++11 -stdlib=libc++  

Ci sono molte buone risposte qui, ma siccome sono arrivato da solo in autonomia prima di leggere questo, ho pensato di buttare il mio qui comunque …

Ecco un metodo che sto usando per questo che funzionerà universalmente su compilatori e piattaforms:

Crea una struct o una class come contenitore per la tua collezione di oggetti. Definire una funzione di sovraccarico dell’operatore per < <.

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

Puoi creare funzioni che prendono la tua struct come parametro, ad esempio:

 someFunc( MyObjectList &objects ); 

Quindi, puoi chiamare quella funzione, in questo modo:

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

In questo modo, puoi creare e passare una raccolta di oggetti di dimensioni dinamiche a una funzione in un'unica riga pulita!

 // 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 vArrayA(sizeOfA); // make room for all // array A integers // and initialize them to 0 for(unsigned i=0; i vArrayB; // declare vector vArrayB for (unsigned i=0; i vArrayC; // create an empty vector vArrayC vArrayC.resize(sizeof(C)/sizeof(C[0])); // enlarging the number of // contained elements for (unsigned i=0; i 

Se la matrice è:

 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 

“Come posso creare un vettore STL e inizializzarlo come sopra? Qual è il modo migliore per farlo con il minimo sforzo di battitura?”

Il modo più semplice per inizializzare un vettore quando hai inizializzato il tuo array incorporato sta usando un elenco di inizializzatore che è stato introdotto in C ++ 11 .

 // Initializing a vector that holds 2 elements of type int. Initializing: std::vector 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's being called on. Assigning ivec.push_back(30); 

ivec ha una dimensione di 3 elementi dopo l’esecuzione dell’istruzione (istruzione etichettata).

Correlato, è ansible utilizzare quanto segue se si desidera che un vettore sia completamente pronto per essere inserito in una dichiarazione rapida (ad esempio, passando immediatamente a un’altra funzione):

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

funzione di esempio

 template void test(std::vector& values) { for(T value : values) std::cout<  

esempio di uso

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

anche se stai attento al decltype, assicurati che il primo valore sia chiaramente quello che vuoi.

B. Stroustrup descrive un buon modo per concatenare le operazioni in 16.2.10 Selfreference a pagina 464 nell’edizione C ++ 11 del Prog. Lang. dove una funzione restituisce un riferimento, qui modificato in un vettore. In questo modo puoi concatenare come v.pb(1).pb(2).pb(3); ma potrebbe essere troppo lavoro per guadagni così piccoli.

 #include  #include  template class chain { private: std::vector _v; public: chain& pb(T a) { _v.push_back(a); return *this; }; std::vector get() { return _v; }; }; using namespace std; int main(int argc, char const *argv[]) { chain v{}; v.pb(1).pb(2).pb(3); for (auto& i : v.get()) { cout < < i << endl; } return 0; } 

1
2
3