Qual é a maneira mais fácil de inicializar um std :: vector com elementos codificados?


612

Eu posso criar uma matriz e inicializá-la assim:

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

Como crio std::vectore inicializo de forma semelhante elegante?

A melhor maneira que eu sei é:

std::vector<int> ints;

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

Existe uma maneira melhor?


1
Se você não vai alterar o tamanho das entradas após a inicialização, considere usar a matriz tr1.
zr.

@ zr, você me deixou curioso ... se eu precisasse de tamanho fixo, eu não poderia usar matrizes antigas simples? Olhando para tr1 série agora ...
Agnel Kurian

2
tr1::arrayé útil porque as matrizes comuns não fornecem a interface de recipientes STL
Manuel

O título foi alterado para tornar essa questão explicitamente em C ++ 03. Parecia mais fácil do que analisar e corrigir todas as respostas para fazer sentido com o novo padrão C ++.
TED

Isso é chamado de inicialização da lista .
Alan Dawkins

Respostas:


548

Um método seria usar a matriz para inicializar o vetor

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

7
@Agnel Ele funcionará bem sem staticou const, no entanto, ambos tornam mais explícitos como devem ser usados ​​e permitem que o compilador faça otimizações adicionais.
Yacoby

68
Não neguei isso, mas fiquei tentado. Principalmente porque isso poupa quase nada, apenas usando a matriz inicializada em primeiro lugar. No entanto, isso é realmente culpa do C ++, não sua.
TED

2
Você pode explicar por que está usando esses parâmetros ao definir o vetor vec.
DomX23 27/01/12

13
sizeof (array) é uma das poucas exceções que permite obter o tamanho total dos elementos da matriz e NÃO a dimensão do ponteiro arr. Então, basicamente, ele está usando o vetor (ponteiro_do_primeiro_elemento, ponteiro_do_elemento_do_elemento + tamanho_em_bytes_of_the_whole_array / size_of_one_element) que é: vetor (ponteiro_do_first_element, ponteiro_do_final_elemento). O tipo já é fornecido com o <int>, portanto o vetor sabe quanto é um elemento. Lembre-se que iterators pode ser tratado como ponteiros para que você está usando basicamente o vetor (iterator começar, iterador final) construtor
Johnny Pauling

11
@TED: Às vezes você precisa modificar o vetor resultante. Por exemplo, você pode precisar sempre ter alguns parâmetros padrão e, às vezes, adicionar alguns personalizados a eles.
DarkWanderer

642

Se o seu compilador suportar C ++ 11, você pode simplesmente:

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

Está disponível no GCC a partir da versão 4.4 . Infelizmente, o VC ++ 2010 parece estar atrasado nesse aspecto.

Como alternativa, a biblioteca Boost.Assign usa magia não macro para permitir o seguinte:

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

Ou:

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

Mas lembre-se de que isso tem alguma sobrecarga (basicamente, list_ofconstrói um std::dequesob o capô); portanto, para um código crítico de desempenho, seria melhor fazer o que Yacoby diz.


Como os vetores são dimensionados automaticamente, seria bom inicializá-lo como vazio também? Como no construtor this->vect = {};:?
Azurespot

3
@Azurespot Você pode apenas inicializá-lo, e ele estará vazio:std::vector<T> vector;
Luke

2
Apenas no caso de alguém pode estar curioso sobre std::vector<int> v = {1, 2, 3, 4};, vetor do initializer list constructorserá chamado para este tipo de inicialização, o seu doc pode ser encontrar na C++ 11seção .
simomo 01/03/19

103

Se você puder, use o modo C ++ [11,14,17, ...] moderno:

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

A velha maneira de fazer um loop em uma matriz de comprimento variável ou usar sizeof()é realmente terrível para os olhos e completamente desnecessária em termos de sobrecarga mental. Que nojo.


2
Para ser justo, essa era originalmente uma questão do C ++ 03, mas espero que as pessoas / empresas adotem os novos padrões. O C ++ ainda precisa de uma implementação de VLA (variável de comprimento variável) na biblioteca padrão semelhante à disponível no Eigen e no Boost.
Adam Erickson

Infelizmente, essa abordagem é problemática em alguns casos, por exemplo, open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467 . Que nojo.
Lightness Races em órbita

Se a "inicialização da lista de um agregado a partir de um objeto do mesmo tipo" é a sua opção, provavelmente há problemas maiores em sua base de código ... Não consigo pensar em nenhum aplicativo em que justificasse os problemas de depuração.
Adam Erickson

77

No C ++ 0x, você poderá fazer da mesma maneira que fez com uma matriz, mas não no padrão atual.

Com apenas suporte ao idioma, você pode usar:

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

Se você pode adicionar outras bibliotecas, tente o boost :: assignment:

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

Para evitar codificar o tamanho de uma 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))

É claro que não reduzi o voto, mas tenho uma pergunta de qualquer maneira: quando o tamanho de uma matriz não é um tempo de compilação constante? Ou seja, em quais casos você usaria a primeira solução no seu segundo snippet em oposição à terceira?
Manuel

4
@Manuel, o tamanho da matriz faz parte do tipo e, como tal, é uma constante de tempo de compilação. Agora, a opção 1 usa essa constante de tempo de compilação 'N' como valor de retorno para uma função. O retorno de uma função não é um tempo de compilação, mas um valor de tempo de execução, mesmo que provavelmente seja incorporado como o valor constante no local da chamada. A diferença é que você não pode fazer: int another[size_of_array(array)]enquanto você pode fazer int another[ARRAY_SIZE(array)].
David Rodríguez - dribeas

1
Na opção 3: eu realmente não entendi o que você quer dizer com "declarado, indefinido"? Então a variável não terá memória adicional?
To1ne

1
@ To1ne que é realmente uma declaração de função, não uma variável. O motivo ou a definição é que na verdade não queremos a função para outra coisa senão a sizeofexpressão que não precisa de uma definição. Embora você possa realmente fornecer uma definição, fazê-lo corretamente exigiria a alocação estática de uma matriz e retornaria uma referência a ela, e a próxima pergunta seria o que faria sentido como valores para a matriz? (Observe também que isso significa uma matriz por combinação de tipo / tamanho das instanciações da função!) Como o uso não é sensato, prefiro evitá-lo.
David Rodríguez - dribeas

1
@mhd: Você não pode construir uma matriz vazia no idioma. 'int arr [0] = {};' não é um código C ++ válido. Mas você está certo de que, se você deseja inicializar um vetor vazio e um vetor não vazio, precisará usar construções diferentes. Desde C ++ 11 este é um não-problema, como você pode usar a lista de inicializador de construtor
David Rodríguez - dribeas

61

No 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 o boost assign:

#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 com macros genéricas:

#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 com uma macro de inicialização de vetor:

#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
O C ++ 11 também suporta std::begine std::endpara array, para que um vetor também possa ser inicializado static const int arr[] = {10,20,30}; vector<int> vec(begin(arr), end(arr));.
Jaege 17/12/16

54

Só pensei em jogar meus $ 0,02. Costumo declarar isso:

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

em um cabeçalho de utilitário em algum lugar e, em seguida, tudo o que é necessário é:

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

Mas mal posso esperar pelo C ++ 0x. Estou preso porque meu código também deve ser compilado no Visual Studio. Vaia.


1
Essa técnica também pode ser usada para sobrecarregar uma função para aceitar uma matriz com tamanho digitado.
Andres Riofrio

4
Você pode explicar a const T (&data)[N]parte? Como é deduzido o tamanho da matriz na sua chamada makeVector(values)?
Patryk

36

Antes do 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 em diante também é possível

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

28

Começando com:

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

Se você não possui um compilador C ++ 11 e não deseja usar o boost:

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

Se você não possui um compilador C ++ 11 e pode usar o boost:

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

Se você possui um compilador C ++ 11:

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

22

Para inicialização de vetor -

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

Isso pode ser feito se você tiver o compilador c ++ 11.

Senão, você pode ter uma matriz de dados e usar um loop for.

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

Além disso, existem várias outras maneiras descritas acima usando algum código. Na minha opinião, essas maneiras são fáceis de lembrar e rápidas de escrever.



16

Eu construo minha própria solução usando va_arg. Esta solução é compatível com 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;
}

Demo


14

Se o seu compilador suportar macros Variadic (o que é verdadeiro para a maioria dos compiladores modernos), você poderá usar a macro a seguir para transformar a inicialização de vetor em uma linha única:

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

Com essa macro, você pode definir um vetor inicializado com código como este:

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

Isso criaria um novo vetor de ints chamado my_vector com os elementos 1, 2, 3, 4.


13

Se você não deseja usar o impulso, mas deseja desfrutar de sintaxe como

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

basta incluir este pedaço 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
Não consegui descobrir como usar esse código, mas parece interessante.
precisa

É como um dos comentários acima dito. Apenas sobrecarregando + = e operador de vírgula. Colocando parênteses para maior clareza: ((((v+=1),2),3),4),5) É assim que funciona: primeiro, vector<T> += Tretorna um vetor_inserter, vamos chamá-lo vique encapsula o vetor original e depois vi,Tadiciona T ao vetor original que viencapsula e retorna a si próprio para que possamos fazer vi,Tnovamente.
Piti Ongmongkolkul

esse código não funcionou corretamente no gcc 4.2.1, acho que devido ao retorno de referência a uma variável local dentro do operador + =, mas a idéia é excelente. Eu editei o código e aparece mais um construtor de cópias. o fluxo agora é -> + = -> ctor -> vírgula -> cópia -> dtor -> vírgula ...... -> vírgula -> dtor.
2013

Eu provavelmente teria sobrecarregado << em vez de + =. Pelo menos << já tem regras vagas de efeitos colaterais por causa de mudanças bits e cout
Speed8ump

11

No C ++ 11:

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

21
Se você já usa o C ++ 11, pode optar pela abordagem direta - vector<int> arr = {10, 20, 30};.
Bernhard Barker

Na verdade, eu tinha um int [] recebido (alguns C lib) e queria inserir um vetor (C ++ lib). Esta resposta ajudou, o resto não ;-)
Nebula

10

você pode fazer isso usando boost :: assign.

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

detalhe aqui


19
Não vejo um caso pior de operador sobrecarregando abusos há muito tempo. Será que +=existe uma aderência a 1,2,3,4 .. no final dos valores ou adiciona 1 ao 1º elemento, 2 ao 2º elemento, 3 ao 3º elemento (como uma sintaxe como essa no MATLAB- como idiomas)
bobobobo

10

Uma pergunta duplicada mais recente tem essa resposta de Viktor Sehr . Para mim, é compacto, visualmente atraente (parece que você está 'empurrando' os valores), não requer c ++ 11 ou um módulo de terceiros e evita o uso de uma variável extra (escrita). Abaixo está como eu o uso com algumas alterações. Eu posso mudar para estender a função de vetor e / ou va_arg no futuro.


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

Os métodos abaixo podem ser usados ​​para inicializar o vetor em 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); e assim por diante

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

O terceiro é permitido apenas no C ++ 11 em diante.


5

Há muitas respostas boas aqui, mas desde que cheguei sozinha antes de ler isso, achei que jogaria as minhas aqui de qualquer maneira ...

Aqui está um método que estou usando para isso que funcionará universalmente em compiladores e plataformas:

Crie uma estrutura ou classe como um contêiner para sua coleção de objetos. Defina uma função de sobrecarga do operador para <<.

class MyObject;

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

Você pode criar funções que tomam sua estrutura como um parâmetro, por exemplo:

someFunc( MyObjectList &objects );

Em seguida, você pode chamar essa função, assim:

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

Dessa forma, você pode criar e transmitir uma coleção de objetos de tamanho dinâmico para uma função em uma única linha limpa!


4

Se você deseja algo na mesma ordem geral que o Boost :: assign sem criar uma dependência do Boost, o seguinte é pelo menos vagamente semelhante:

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

Embora eu deseje que a sintaxe para usá-lo seja mais limpa, ainda não é particularmente terrível:

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, use:

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

Pergunta estados C ++ 03 (não 11)
Mike P

1
Eu acho que não especificou 03 quando eu respondi isso. Não se lembre perfeitamente embora. No entanto, ainda é uma resposta útil para quem procura uma solução 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

Se a matriz for:

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

É bastante conveniente criar um vetor embutido sem definir variável ao escrever teste, por exemplo:

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

3

Relacionado, você pode usar o seguinte se quiser ter um vetor completamente pronto para uma declaração rápida (por exemplo, passar imediatamente para outra função):

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

função de exemplo

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

exemplo de uso

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

embora tenha cuidado com o decltype, verifique se o primeiro valor é claramente o que você deseja.


3

Existem várias maneiras de codificar um vetor, compartilharei algumas maneiras:

  1. Inicializando pressionando valores um por um
// Create an empty vector 
    vector<int> vect;  

    vect.push_back(10); 
    vect.push_back(20); 
    vect.push_back(30); 
  1. Inicializando como matrizes
vector<int> vect{ 10, 20, 30 };
  1. Inicializando a partir de uma matriz
    int arr[] = { 10, 20, 30 }; 
    int n = sizeof(arr) / sizeof(arr[0]); 

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

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

2

"Como crio um vetor STL e o inicializo como acima? Qual é a melhor maneira de fazer isso com o mínimo esforço de digitação?"

A maneira mais fácil de inicializar um vetor quando você inicializou sua matriz interna é usando uma lista de inicializadores que foi introduzida no 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 tem 3 elementos em tamanho após a execução de Assigning (instrução rotulada).


Nas linhas semelhantes, estou tentando inicializar o mapa, std :: map <int, bool> catinfo = {{1, false}}; Mas, em seguida, obtenha este erro de erro: no C ++ 98 'catinfo' deve ser inicializado pelo construtor, não por '{...}'
pdk

2

B. Stroustrup descreve uma boa maneira de encadear operações na 16.2.10 Selfreference na página 464 na edição C ++ 11 do Prog. Lang. onde uma função retorna uma referência, modificada aqui para um vetor. Dessa forma, você pode encadear como, v.pb(1).pb(2).pb(3);mas pode ser muito trabalhoso para ganhos tão pequenos.

#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


A biblioteca tatu faz isso para inicialização de matriz mas usa o << operador em vez de uma função chamada: arma.sourceforge.net/docs.html#element_initialisation
Agnel Kurian

0

A maneira mais simples e ergonômica (com C ++ 11 ou posterior):

auto my_ints = {1,2,3};

0

Caso você queira tê-lo em sua própria classe:

#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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.