- Como se adicionar valores a um vetor em C++?
- Adicionar valores a um vetor em C++ – Método #1 – push_back
- Adicionar valores a um vetor em C++ – Método #2 – emplace_back
- Adicionar valores a um vetor em C++ – Método #3 – emplace
- Adicionar valores a um vetor em C++ – Métodos #4, #5, #6 e #7 – insert
- Conclusão
Como se adicionar valores a um vetor em C++?
Com a introdução dos novos containeres da linguagem (array, vector, deque etc.), pode ser complicado saber qual método usar para adicionar valores a um vetor em C++. Por essa razão decidi escrever esse artigo como uma referência rápida do assunto.
Há várias formas de se adicionar valores a um vetor em C++, dentre as quais as 7 maneiras a seguir podem ser usadas com os vetores (do tipo vector
da biblioteca padrão std
): push_back, emplace_back, emplace (2 sobrecargas), insert (4 sobrecargas).
Vejamos, então, como funcionam cada uma dessas formas e como utilizá-las com exemplos.
Adicionar valores a um vetor em C++ – Método #1 – push_back
Este provavelmente é o método mais utilizado para se adicionar valores a um vetor em C++. O push_back
é muito simples: ele adiciona um elemento no final do vetor. Para usá-lo basta seguir a sintaxe a seguir: nome-do-vetor.push_back(elemento-a-ser-adicionado-ao-vetor)
. Aqui vale lembrar que o elemento a ser adicionado no vetor deve ser do mesmo tipo dos elementos armazenados no vetor, e que o retorno do push_back
é void. Vejamos abaixo um exemplo de uso do push_back
com um vetor de inteiros.
/********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #1 - push_back ***********************************************/ #include <iostream> #include <vector> int main() { std::vector<int> intVector = {10, 20, 30}; intVector.push_back(40); for (const auto& intValue : intVector) { std::cout << intValue << " "; } return 0; }
Adicionar valores a um vetor em C++ – Método #2 – emplace_back
O segundo modo de se adicionar valores a um vetor em C++ é o emplace_back
. Da mesma forma que o método push_back
, o método emplace_back
adiciona um elemento no fim do vetor; a diferença, emtretanto, está nos valores que os dois recebem e como o elemento é adicionado.
O argumento de entrada do emplace_back
é o valor (ou os valores) utilizados para construir o objeto que será armazenado no vetor. Se tomarmos por exemplo o vetor declarado como a seguir: std::vector<Pessoa> vetorPessoa
, em que Person
é um struct cujo construtor recebe um string
e um inteiro (que representam respectivamente o nome e a idade de uma pessoa), para adicionar-lhe um novo objeto a partir das informações da pessoa que desejamos criar, podemos utilizar o emplace_back
da seguinte maneira: vetorPessoa.emplace_back("Bruno", 34);
.
A vantagem do emplace_back
em relação ao push_back
é esta: no emplace_back
o objeto é criado e movido diretamente para o vetor, enquanto no push_back
uma cópia do objeto da entrada da função é criada e adicionada ao vetor. O retorno do método emplace_back
, assim como o do push_back
é void.
Vejamos abaixo um exemplo de uso do emplace_back
para adicionar uma pessoa a um vetor de pessoas.
/********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #2 - emplace_back ***********************************************/ #include <iostream> #include <vector> struct Person { Person() = default; // Esse é o construtor utilizado pelo emplace_back para criar // a nova pessoa (objeto de tipo Person) direto no vetor, sem cópias. Person(const std::string& iName, const int& iAge) : name(iName), age(iAge) {} std::string name; int age; }; int main() { std::vector<Person> personVector; personVector.emplace_back("Rodinei", 40); personVector.emplace_back("Ricardo", 35); for (const auto& aPerson : personVector) { std::cout << "{" << aPerson.name << " - " << aPerson.age << "} "; } return 0; }
Adicionar valores a um vetor em C++ – Método #3 – emplace
Assim com o seu parente emplace_back
, o método emplace
é usado para adicionar um elemento a um vetor sem copiá-lo, mas construindo o objeto e movendo para o vetor. A diferença entre o emplace
e o emplace_back
é a seguinte: o emplace
permite que o usuário adicione o elemento a uma posição qualquer do vetor, e não apenas no fim.
Logo, por permitir inserir um novo objeto em uma posição qualquer do vetor, o método emplace
tem que ser informado de algum modo onde é que se deseja inserir o elemento no vetor, e isso é feito através do uso de um iterador (veja a seção “For loop usando iteradores” do nosso artigo sobre como percorrer arrays). O novo elemento é inserido imediatamente antes do iterador passado como argumento para a função emplace
. Logo, a sintaxe para se adicionar um novo valor a um vetor em C++ usando essa função é a seguinte: variavelVector.emplace(iterator, argumentos-para-construir-um-objeto-do-tipo-do-vetor)
. Além disso, é importante notar que o retorno do método emplace
é um iterator para o elemento que foi adicionado ao vetor.
Vejamos a seguir um exemplo do uso do emplace
para adicionar objetos do tipo Person
(do nosso exemplo anterior) a um vetor.
/*********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #3 - emplace ************************************************/ #include <iostream> #include <vector> struct Person { Person() = default; // Esse é o construtor utilizado pelo emplace para criar // a nova pessoa (objeto de tipo Person) direto no vetor, sem cópias. Person(const std::string& iName, const int& iAge) : name(iName), age(iAge) {} std::string name; int age; }; int main() { std::vector<Person> personVector; // A pessoa com nome Bruno e idade 40 é adicionada ao fim do vetor. // O const_iterator aConstIterator é inicializado com o retorno do // emplace, e ele aponta para o objeto adicionado ao vetor. std::vector<Person>::const_iterator aConstIterator = personVector.emplace(personVector.cend(), "Bruno", 40); // Ricardo, de 35 anos, é adicionado antes de Bruno. // Essa operação não é recomendada é vetores, pois insere // elementos em um lugar diferente do fim do container e requer // o deslocamento dos outros elementos. personVector.emplace(aConstIterator, "Ricardo", 35); // Maria, de 28 anos, é adicionada ao início do vetor. // Isso também não é recomendável, pela mesma razão do emplace anterior. personVector.emplace(personVector.cbegin(), "Maria", 28); for (const auto& aPerson : personVector) { std::cout << "{" << aPerson.name << " - " << aPerson.age << "} "; } return 0; }
Para compreender melhor o exemplo anterior, aqui está uma análise rápida do que acontece nele:
Bons hábitos – #1 use iteradores constantes sempre que possível
Sempre que se for usar um iterador apenas para ler valores de um container, e não para modificá-los, use as versões constantes dos iteradores (obtidas com cbegin() e cend()). Desta forma, previnem-se modificações indesejadas dos elementos do container, mas também a intenção do código (de não modificar nada) fica clara pelo uso do iterador constante.
Bons hábitos – #2 adicione elementos apenas no fim de um vetor
Sempre que possível, evite adicionar elementos a um container de tipo vector em outras posições além do final, pois isso requer que outros elementos sejam movidos no container, o que torna a adição do elemento uma operação custosa. Isso é especialmente importante ao se adicionar elementos ao início de um vetor.
Se você precisar adicionar elementos ao início de um vetor, veja se não é possível usar um outro container, como o deque, por exemplo.
Adicionar valores a um vetor em C++ – Métodos #4, #5, #6 e #7 – insert
Chegamos ao último método utilizado para se adicionar valores a um vetor em C++: o insert
. Na verdade, ele vale por 4, porque possui 4 assinaturas diferentes que permitem utilizá-lo com bastante flexibilidade. Por essa mesma razão, irei dividir essa seção em subseções, uma para cada “versão” do método insert
.
Métodos #4 – insert(iterator, value)
A versão de base do método insert
é insert(iterator, value)
, na qual os dois argumentos são o que sugerem seus nomes: iterator
é um iterador para uma posição no vetor (que pode também apontar para uma posição além do fim do vetor, como retornado pelos métodos end()
e cend()
); value
é o valor a ser adicionado no vetor antes da posição de iterador
. O valor de retorno do método insert
é um iterador que aponta para o elemento que foi adicionado. Vejamos um exemplo com um vetor de pessoas (Person
).
/*********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #4 - insert(iterator, value) ************************************************/ #include <iostream> #include <vector> struct Person { Person() = default; Person(const std::string& iName, const int& iAge) : name(iName), age(iAge) {} std::string name; int age; }; int main() { std::vector<Person> personVector; std::vector<Person>::const_iterator aConstIterator = personVector.end(); const Person aRicardo{"Ricardo", 35}; // O iterador aConstIterator é atualizado para apontar para a pessoa // que acabou de ser adicionada no vetor. aConstIterator = personVector.insert(aConstIterator, aRicardo); // Maria é adicionada antes de Ricardo. const Person aMaria = {"Maria", 28}; personVector.insert(aConstIterator, aMaria); for (const auto& aPerson : personVector) { std::cout << "{" << aPerson.name << " - " << aPerson.age << "} "; } return 0; }
Métodos #5 – insert(iterator, count, value)
Assim como a versão anterior de insert
, a sobrecarga desse método que possue a assinatura insert(iterator, count, value)
também usa um iterador (iterator
) para determinar onde serão adicionados os elementos novos. Contudo, ao invés de adicionar apenas uma cópia de value
no vetor antes da posição determinada por iterator
, essa versao do método adiciona count
cópias do novo objeto ao vetor. O seu retorno é um iterador que aponta para o primeiro elemento adicionado – caso count
seja 0, o retorno da função é o próprio argumento iterator
.
Vejamos um exemplo do uso dessa função com nosso vetor de pessoas.
/*********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #5 - insert(iterator, count, value) ************************************************/ #include <iostream> #include <vector> struct Person { Person() = default; Person(const std::string& iName, const int& iAge) : name(iName), age(iAge) {} std::string name; int age; }; int main() { std::vector<Person> personVector; std::vector<Person>::const_iterator aConstIterator = personVector.end(); const Person aRicardo{"Ricardo", 35}; // 3 cópias de aRicardo são adicionadas ao vetor aConstIterator = personVector.insert(aConstIterator, 3, aRicardo); for (const auto& aPerson : personVector) { std::cout << "{" << aPerson.name << " - " << aPerson.age << "} "; } return 0; }
Métodos #6 – insert(iterator, iterBeg, iterEnd)
Chegamos a uma versão um tanto quanto diferente do método insert
. Nessa sobrecarga, cuja assinatura é a seguinte insert(iterator, iterBeg, iterEnd)
, há o argumento de sempre: iterator
, que indica onde os novos elementos serão adicionados, mas também há dois novos que são completamente diferentes: iterBeg
e iterEnd
, que são dois iteradores que determinam uma “faixa” de valores pertencentes a outro container (vetor, lista, deque etc.) que contenha elementos do mesmo tipo do vetor onde queremos adicionar novos valores.
Vale notar também que o intervalo de valores determinado por iterBeg
e iterEnd
é um intervalo do seguinte formato: [iterBeg
, iterEnd
). Para os que não estão familiarizados com a notacão matemática, isto apenas significa que o elemento apontado por iterBeg
será copiado para o novo vetor, mas aquele apontado por iterEnd
não o será. Outro ponto importanto: os iteradores iterBeg
e iterEnd
devem apontar para o vetor de destino dos novos elementos – isto resultaria em um comportamento indeterminado do programa. Além disso, o retorno da função é um iterador para o primeiro elemento adicionado, ou o próprio argumento iterator
se iterBeg == iterEnd
.
Vejamos abaixo um exemplo do uso dessa sobrecarga do método insert
para copiar inteiros pares para um vetor de inteiros ímpares (caso não entenda bem as linhas 19 e 20, veja nosso artigo sobre operações com ponteiros).
/*********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #6 - insert(iterator, iterBeg, iterEnd) ************************************************/ #include <iostream> #include <vector> int main() { std::vector<int> evenVector{2, 4, 6, 8, 10}; // Vetor de números pares std::vector<int> oddVector{1, 3, 5, 7, 9}; // Vetor de números ímpares // aInsertionPosition aponta para o número "9", ou seja, // os novos valores serão adicionados antes dele. std::vector<int>::const_iterator aInsertionPosition = oddVector.cend() - 1; // aIterBeg aponta para o dígito "4" e aIterEnd para o número 10. // Logo, os valores copiados serão 4, 6 e 8 (o 10 não está incluído no intervalo) std::vector<int>::const_iterator aIterBeg = evenVector.cbegin() + 1; std::vector<int>::const_iterator aIterEnd = evenVector.cend() -1; oddVector.insert(aInsertionPosition, aIterBeg, aIterEnd); for (const auto aInt : oddVector) { std::cout << aInt << " "; } return 0; }
Métodos #7 – insert(iterator, initializerList)
Chegamos ao último modo de se adicionar valores a um vetor em C++: a sobrecarga insert(iterator, initializerList)
do nosso conhecido método insert. Esta versão é um pouco mais simples que as demais, pois ela possui apenas dois parâmetros: iterator
que indica onde os novos elementos serão adicionados, e initializerList
, uma lista (entre chaves { }) contendo os novos valores a serem adicionados ao vetor (eles devem ser do mesmo tipo dos objetos no vetor de destino). Seu retorno é um iterador para o primeiro elemento adicionado, ou o próprio iterator
caso initializerList
esteja vazia.
A seguir temos um exemplo do uso dessa sobrecarga do método insert
para inserir novos valores a um vetor de inteiros.
/*********************************************** * C++ Moderno © * Como se adicionar valores a um vetor em C++ * Exemplo #7 - insert(iterator, initializerList) ************************************************/ #include <iostream> #include <vector> int main() { std::vector<int> oddVector{1, 3, 5, 7, 9}; // Vetor de números ímpares // aInsertionPosition aponta para o número "9", ou seja, // os novos valores serão adicionados antes dele. std::vector<int>::const_iterator aInsertionPosition = oddVector.cend() - 1; // Os elementos 4, 6 e 8 são adicionados ao vetor, assim como foi feito // no exemplo #6. oddVector.insert(aInsertionPosition, {4, 6, 8}); for (const auto aInt : oddVector) { std::cout << aInt << " "; } return 0; }
Conclusão
Neste artigo vimos 7 formas de se adicionar valores a um vetor em C++. A primeira delas é o push_back
, que copia um elemento para o vetor. A segunda e a terceira são emplace_back
e emplace
, que permitem adicionar um elemento diretamente ao vetor sem copiá-lo, com a diferença de que a primeira permite adicioná-lo apenas ao fim do vetor. As 4 restantes são as sobrecargas do método insert
(para mais detalhes, veja o artigo do CppReference), que permitem copiar elementos para o vetor a partir de várias fontes diferentes (outros vetores, listas de inicialização etc.) e de modos diferentes.
Se você gostou deste artigo e gostaria de ver outros semelhantes sobre um assunto que você tem em mente, fique à vontade para me dizê-lo nos comentários 😉
Sou apaixonado por tecnologia, literatura e também filosofia. O cultivo dessas paixões ao longo da minha trajetória me inspiraram a compartilhar aquilo que aprendo com os outros da maneira mais clara que eu possa. Sou formado em Engenharia Elétrica no Brasil, e também sou engenheiro formado na França. Trabalho atualmente como programador C++ em uma multinacional francesa, uma das maiores empresas de TI do mundo.