Como adicionar valores a um vetor em C++? 7 métodos explicados com exemplos

lista dos métodos usados para adicionar valores a um vetor em C++ (push_back, emplace_back, emplace e insert) ao lado de uma pilha de pedras sobre uma lâmina de água.

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

10 20 30 40

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

{Rodinei – 40} {Ricardo – 35}

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

{Maria – 28} {Ricardo – 35} {Bruno – 40}

Para compreender melhor o exemplo anterior, aqui está uma análise rápida do que acontece nele:

  • Na linha 24 adiciona-se o objeto de tipo Person com nome “Bruno”e idade 40 no vetor de pessoas, e ele é adicionado ao fim do container (que está vazio neste ponto). O retorno da operação emplace é um iterador que aponta para o novo objeto adicionado no container, então o armazenamos na variável aConstIterator, que é um iterador constante do vetor de pessoas.
  • Na linha 29 uma outra pessoa com nome “Ricardo” e idade de 35 anos é adicionada ao vetor antes de Bruno, pois passamos como argumento o iterador aConstIterator, que aponta para o objeto “Bruno”.
  • Na linha 32 é adicionado um último objeto ao vetor personVector: Maria, de 28 anos. Todavia, Maria é adicionada no início do vetor, pois é passado como primeiro argumento de emplace o iterador que aponta para o primeiro elemento do container usando o método cbegin() (que retorna um iterador constante).
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;
}

{Maria – 28} {Ricardo – 35}

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

{Ricardo – 35} {Ricardo – 35} {Ricardo – 35}

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

1 3 5 7 4 6 8 9

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

1 3 5 7 4 6 8 9

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 😉

Foto de perfil de Emanoel

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.

Leave a Reply

Your email address will not be published. Required fields are marked *