¿Cuál es la forma más fácil de inicializar un std :: vector con elementos codificados?


612

Puedo crear una matriz e inicializarla así:

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

¿Cómo creo un std::vector e inicializo un estilo igualmente elegante?

La mejor manera que sé es:

std::vector<int> ints;

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

¿Hay una mejor manera?


1
Si no va a cambiar el tamaño de las entradas después de la inicialización, considere usar la matriz tr1.
zr.

@zr, tienes curiosidad ... si necesito un tamaño fijo, ¿no podría usar matrices antiguas simples? Mirando la matriz tr1 en este momento ...
Agnel Kurian

2
tr1::arrayes útil porque las matrices ordinarias no proporcionan la interfaz de los contenedores STL
Manuel

Cambió el título para hacer esto explícitamente una pregunta C ++ 03. Parecía más fácil que revisar y corregir todas las respuestas para tener sentido con el nuevo estándar C ++.
TED

Respuestas:


548

Un método sería usar la matriz para inicializar el vector

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

77
@Agnel Funcionará bien sin statico const, sin embargo, ambos lo hacen más explícito sobre cómo debe usarse y permiten que el compilador realice optimizaciones adicionales.
Yacoby

68
No desestimé esto, pero me sentí tentado. Principalmente porque esto le ahorra casi nada más que solo usar la matriz inicializada en primer lugar. Sin embargo, eso es realmente culpa de C ++, no tuya.
TED

2
¿Puede explicar por qué está usando esos parámetros al definir el vector vec?
DomX23

13
sizeof (array) es una de las pocas excepciones que permite obtener el tamaño total de los elementos de la matriz y NO la dimensión del puntero arr. Entonces, básicamente, está usando vector (pointer_to_first_element, pointer_to_first_element + size_in_bytes_of_the_whole_array / size_of_one_element) que es: vector (pointer_to_first_element, pointer_after_final_element). El tipo ya está dado con <int>, por lo que el vector sabe cuánto es un elemento. Recuerde que los iteradores pueden tratarse como punteros, por lo que básicamente está utilizando el constructor de vectores (comienzo del iterador, final del iterador)
Johnny Pauling

11
@TED: a veces es necesario modificar el vector resultante. Por ejemplo, es posible que deba tener siempre algunos parámetros predeterminados y, a veces, agregar algunos personalizados.
DarkWanderer

642

Si su compilador admite C ++ 11, simplemente puede hacer:

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

Está disponible en GCC a partir de la versión 4.4 . Desafortunadamente, VC ++ 2010 parece estar rezagado a este respecto.

Alternativamente, la biblioteca Boost.Assign usa magia no macro para permitir lo siguiente:

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

O:

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

Pero tenga en cuenta que esto tiene algo de sobrecarga (básicamente, list_ofconstruye un std::dequebajo el capó), por lo que para un código crítico de rendimiento sería mejor que haga como dice Yacoby.


Dado que los vectores son de tamaño propio, ¿estaría bien inicializarlo también como vacío? Como en el constructor this->vect = {};:?
Azurespot

3
@Azurespot Puede simplemente inicializarlo, y estará vacío:std::vector<T> vector;
Lucas

2
En caso de que alguien tenga curiosidad std::vector<int> v = {1, 2, 3, 4};, los vectores initializer list constructorse llamarán para este tipo de inicialización, su documento se puede encontrar en la C++ 11sección .
simomo

103

Si puede, use el moderno C ++ [11,14,17, ...]:

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

La antigua forma de bucle sobre una matriz de longitud variable o uso sizeof()es realmente terrible a los ojos y completamente innecesaria en términos de sobrecarga mental. Yuck


2
Para ser justos, originalmente era una pregunta de C ++ 03, pero espero que las personas / empresas adopten los nuevos estándares. C ++ todavía necesita una implementación de matriz de longitud variable (VLA) en la biblioteca estándar similar a la que está disponible en Eigen y Boost.
Adam Erickson

Desafortunadamente, este enfoque es problemático en algunos casos, por ejemplo, open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467 . Yuck
ligereza corre en órbita

Si la "inicialización de la lista de un agregado de un objeto del mismo tipo" es lo suyo, probablemente haya problemas más grandes en su base de código ... No puedo pensar en ninguna aplicación donde justifique los problemas de depuración.
Adam Erickson

77

En C ++ 0x podrá hacerlo de la misma manera que lo hizo con una matriz, pero no en el estándar actual.

Con solo soporte de idiomas puede usar:

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

Si puede agregar otras bibliotecas, puede intentar aumentar :: asignación:

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

Para evitar codificar el tamaño de una matriz:

// 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))

Por supuesto que no voté en contra, pero tengo una pregunta de todos modos: ¿cuándo el tamaño de una matriz no es una constante de tiempo de compilación? Es decir, ¿en qué casos usaría la primera solución en su segundo fragmento en lugar de la tercera?
Manuel

44
@Manuel, el tamaño de la matriz es parte del tipo, y como tal es una constante de tiempo de compilación. Ahora, la opción 1 usa esa constante de tiempo de compilación 'N' como valor de retorno para una función. El retorno de una función no es un tiempo de compilación, sino un valor de tiempo de ejecución, incluso si probablemente se incorporará como el valor constante en el lugar de la llamada. La diferencia es que no puedes hacer int another[size_of_array(array)], mientras que puedes hacer int another[ARRAY_SIZE(array)].
David Rodríguez - dribeas

1
En la opción 3: ¿Realmente no entiendo lo que quieres decir con "declarado, indefinido"? Entonces, ¿la variable no tomará memoria adicional?
To1ne

1
@ To1ne que en realidad es una declaración de función, no una variable. La razón o la definición es que en realidad no queremos la función para otra cosa que no sea la sizeofexpresión que no necesita una definición. Si bien puede proporcionar una definición, hacerlo correctamente requeriría la asignación estática de una matriz y devolverle una referencia, y la siguiente pregunta sería ¿qué tendría sentido como valores para la matriz? (¡Tenga en cuenta también que esto significa una combinación de matriz por tipo / tamaño de las instancias de la función!) Dado que no es un uso razonable para ella, prefiero evitarla.
David Rodríguez - dribeas

1
@mhd: no puede construir una matriz vacía en el idioma. 'int arr [0] = {};' No es un código C ++ válido. Pero tiene razón en que si desea inicializar un vector vacío y un vector no vacío, tendrá que usar diferentes construcciones. Desde C ++ 11 esto no es un problema, ya que puede usar el constructor de la lista de inicializadores
David Rodríguez - dribeas

61

En C ++ 11:

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

Usando boost list_of:

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

Usando la asignación de impulso:

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

STL convencional:

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

STL convencional con macros genéricos:

#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 convencional con una macro de inicializador de vector:

#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);

2
C ++ 11 también admite std::beginy std::endpara array, por lo que un vector también se puede inicializar como static const int arr[] = {10,20,30}; vector<int> vec(begin(arr), end(arr));.
Jaege

54

Solo pensé en tirar mis $ 0.02. Tiendo a declarar esto:

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

en un encabezado de utilidad en algún lugar y luego todo lo que se requiere es:

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

Pero no puedo esperar a C ++ 0x. Estoy atascado porque mi código también debe compilarse en Visual Studio. Abucheo.


1
Esta técnica también se puede utilizar para sobrecargar una función para aceptar una matriz con un tamaño escrito.
Andres Riofrio

44
¿Puedes explicar la const T (&data)[N]parte? ¿Cómo se deduce el tamaño de la matriz en su llamada makeVector(values)?
Patryk

36

Antes de C ++ 11:

Método 1 =>

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

Método 2 =>

 v.push_back(SomeValue);

C ++ 11 en adelante a continuación también es posible

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

28

Empezando con:

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

Si no tiene un compilador de C ++ 11 y no desea usar boost:

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

Si no tiene un compilador de C ++ 11 y puede usar boost:

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

Si tienes un compilador de C ++ 11:

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

22

Para la inicialización del vector:

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

se puede hacer si tienes el compilador de c ++ 11.

De lo contrario, puede tener una matriz de datos y luego usar un bucle for.

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

Además de estos, hay varias otras formas descritas anteriormente utilizando algún código. En mi opinión, estas formas son fáciles de recordar y rápidas de escribir.



16

Construyo mi propia solución usando va_arg. Esta solución es compatible con C ++ 98.

#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;
}

Manifestación


14

Si su compilador admite macros Variadic (lo cual es cierto para la mayoría de los compiladores modernos), puede usar la siguiente macro para convertir la inicialización de vectores en una línea:

#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))

Con esta macro, puede definir un vector inicializado con un código como este:

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

Esto crearía un nuevo vector de entradas llamado my_vector con los elementos 1, 2, 3, 4.


13

Si no quieres usar boost, pero quieres disfrutar de sintaxis como

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

solo incluye este fragmento de código

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
No he podido averiguar cómo usar este código, pero parece interesante.
Daniel Buckmaster

Es como uno de los comentarios mencionados anteriormente. Simplemente sobrecargando + = y operador de coma. Poner paréntesis para mayor claridad: ((((v+=1),2),3),4),5) así es como funciona: Primero, vector<T> += Tdevuelve un vector_inserter, lo llamamos vique encapsula el vector original, luego vi,Tagrega T al vector original que viencapsula y lo devuelve a sí mismo para que podamos vi,Tvolver a hacerlo .
Piti Ongmongkolkul

este código no funcionó correctamente en gcc 4.2.1, creo que debido a la referencia de retorno a una variable local dentro del operador + =, pero la idea es excelente. Edité el código y aparece un constructor de copia más. ahora el flujo es -> + = -> ctor -> coma -> copia -> dtor -> coma ...... -> coma -> dtor.
Yevhen

Probablemente habría sobrecargado << en lugar de + =. Al menos << ya tiene reglas de efectos secundarios vagas debido a cambios de bit y cout
Speed8ump

11

En C ++ 11:

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

21
Si ya está utilizando C ++ 11, también puede optar por el enfoque directo - vector<int> arr = {10, 20, 30};.
Bernhard Barker

En realidad, tenía un int entrante [] (algunos C lib) y quería ingresar a un vector (C ++ lib). Esta respuesta ayudó, el resto no ;-)
Nebula

10

puedes hacerlo usando boost :: asignar.

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

detalle aquí


19
No he visto un caso peor de abuso de sobrecarga del operador en mucho tiempo. ¿ +=Se agrega el valor 1,2,3,4 al final de los valores o se agrega 1 al primer elemento, 2 al segundo elemento, 3 al tercer elemento (como la sintaxis como esta debería en MATLAB- lenguajes similares)
bobobobo

10

Una pregunta duplicada más reciente tiene esta respuesta de Viktor Sehr . Para mí, es compacto, visualmente atractivo (parece que está 'introduciendo' los valores), no requiere c ++ 11 o un módulo de terceros, y evita el uso de una variable adicional (escrita). A continuación se muestra cómo lo estoy usando con algunos cambios. Puedo cambiar a extender la función de vector y / o va_arg en el futuro intead.


// Based on answer by "Viktor Sehr" on Stack Overflow
// https://stackoverflow.com/a/8907356
//
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)

7

Los siguientes métodos se pueden usar para inicializar el vector en c ++.

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

  2. vector<int>v; v.push_back(1); v.push_back(2); v.push_back(3); y así

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

El tercero solo está permitido en C ++ 11 en adelante.


5

Hay muchas buenas respuestas aquí, pero como llegué a mi propia pregunta antes de leer esto, pensé que arrojaría la mía aquí de todos modos ...

Aquí hay un método que estoy usando para esto que funcionará universalmente en compiladores y plataformas:

Cree una estructura o clase como contenedor para su colección de objetos. Defina una función de sobrecarga del operador para <<.

class MyObject;

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

Puede crear funciones que tomen su estructura como parámetro, por ejemplo:

someFunc( MyObjectList &objects );

Entonces, puede llamar a esa función, así:

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

¡De esa manera, puede construir y pasar una colección de objetos de tamaño dinámico a una función en una sola línea limpia!


4

Si desea algo en el mismo orden general que Boost :: asignar sin crear una dependencia en Boost, lo siguiente es al menos vagamente similar:

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);
}

Si bien deseo que la sintaxis para usarla sea más limpia, todavía no es particularmente horrible:

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

4
typedef std::vector<int> arr;

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

Para compilar el uso:

clang++ -std=c++11 -stdlib=libc++  <filename.cpp>

La pregunta dice C ++ 03 (no 11)
Mike P

1
Creo que no especificó 03 cuando respondí esto. Sin embargo, no recuerdo perfectamente. Sin embargo, sigue siendo una respuesta útil para alguien que busca una solución rápida.
shaveenk

4
// 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.

4

Si la matriz es:

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 

4

Es bastante conveniente crear un vector en línea sin definir una variable al escribir una prueba, por ejemplo:

assert(MyFunction() == std::vector<int>{1, 3, 4}); // <- this.

3

Relacionado, puede usar lo siguiente si desea tener un vector completamente listo para ir en una declaración rápida (por ejemplo, pasar inmediatamente a otra función):

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

función de ejemplo

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

ejemplo de uso

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

aunque tenga cuidado con el decltype, asegúrese de que el primer valor sea claramente el que desea.


3

Hay varias formas de codificar un vector, compartiré algunas formas:

  1. Inicializando presionando valores uno por uno
// Create an empty vector 
    vector<int> vect;  

    vect.push_back(10); 
    vect.push_back(20); 
    vect.push_back(30); 
  1. Inicializando como matrices
vector<int> vect{ 10, 20, 30 };
  1. Inicializando desde una matriz
    int arr[] = { 10, 20, 30 }; 
    int n = sizeof(arr) / sizeof(arr[0]); 

    vector<int> vect(arr, arr + n); 
  1. Inicializando desde otro vector
    vector<int> vect1{ 10, 20, 30 }; 

    vector<int> vect2(vect1.begin(), vect1.end()); 

2

"¿Cómo creo un vector STL e inicializo como el anterior? ¿Cuál es la mejor manera de hacerlo con el mínimo esfuerzo de escritura?"

La forma más fácil de inicializar un vector como ha inicializado su matriz incorporada es usar una lista de inicializador que se introdujo en C ++ 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's being called on.
Assigning
ivec.push_back(30);

ivec tiene 3 elementos de tamaño después de ejecutar Asignación (declaración etiquetada).


En las líneas similares, estoy tratando de inicializar el mapa, std :: map <int, bool> catinfo = {{1, false}}; Pero luego obtenga este error de error: en C ++ 98 'catinfo' debe ser inicializado por el constructor, no por '{...}'
pdk

2

B. Stroustrup describe una buena manera de encadenar operaciones en 16.2.10 Self Reference en la página 464 en la edición C ++ 11 del Prog. Lang. donde una función devuelve una referencia, aquí modificada a un vector. De esta manera puede encadenar, v.pb(1).pb(2).pb(3);pero puede ser demasiado trabajo para ganancias tan pequeñas.

#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


La biblioteca de armadillo hace esto para la inicialización de la matriz, pero utiliza el operador << en lugar de una función con nombre: arma.sourceforge.net/docs.html#element_initialisation
Agnel Kurian

0

La forma más simple y ergonómica (con C ++ 11 o posterior):

auto my_ints = {1,2,3};

0

En caso de que quieras tenerlo en tu propia clase:

#include <initializer_list>
Vector<Type>::Vector(std::initializer_list<Type> init_list) : _size(init_list.size()),
_capacity(_size),
_data(new Type[_size])
{
    int idx = 0;
    for (auto it = init_list.begin(); it != init_list.end(); ++it)
        _data[idx++] = *it;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.