Em um dos artigos anteriores, vimos 7 modos de como se adicionar valores a um vetor em C++, portanto achei que fosse a hora de falarmos sobre como remover um elemento de um vetor em C++. Neste artigo, portanto, mostrarei brevemente 6 formas diferentes de se realizar essa tarefa, que são as seguintes:
- pop_back()
- erase(it)
- erase(begIt, endIt)
- remove(begIt, endIt, value)
- remove_if(begIt, endIt, predicate)
- clear()
Método #1 – pop_back()
O método pop_back()
é muito simples: ele serve para remover o último elemento de um vetor. Sua utilização também não tem mistérios, basta invocá-lo como um método de uma classe sobre o vector que você possui. Vejamos a seguir um exemplo de uso do pop_back() para remover um elemento de um vetor em C++.
/********************************************** * Como remover um elemento de um vetor em C++? * Exemplo #1 - pop_back() **********************************************/ #include <iostream> #include <vector> int main() { std::vector<int> intVector{10, 20, 30, 40, 50}; intVector.pop_back(); // Remove o valor 50 do vetor intVector.pop_back(); // Remove o valor 40 do vetor for (const int intValue : intVector) { std::cout << intValue << " "; } return 0; }
A vantagem do uso do pop_back() em relação aos outros métodos que veremos a seguir é a simplicidade de uso e de compreensão: não é preciso passar nenhum argumento para a função e seu nome sugere muito bem o que ela faz (remove um elemento do final do vetor. Contudo, como se pode deduzir, a inconveniência de se usar o pop_back() é a limitação de apenas poder remover o último elemento do vetor.
Método #2 – erase(it)
Quando se deseja remover um elemento de um vetor em C++ diferente do último, já vimos que temos de recorrer a uma ferramenta diferente do pop_back(). Felizmente, há uma outra função que serve precisamente a esse propósito: erase(it)
. Essa função na verdade tem duas sobrecargas: uma que recebe apenas um iterador, e outra que recebe dois iteradores como argumentos de entrada.
A primeira versão da função erase() é utilizada da seguinte forma (considere que intVec
é um vetor de inteiros): intVec.erase(iterador-pos-elemento)
. O iterador passado para a função (iterador-pos-elemento) aponta para a posição do elemento que se deseja remover do vector. Veja no exemplo abaixo o seu uso para remover o último elemento de um vetor (imitando o efeito do pop_back()), e também para remover um elemento no meio desse mesmo vetor (para uma revisão sobre as operações aritméticas com iteradores, visite meu artigo sobre 5 operações com ponteiros em C++).
/********************************************** * Como remover um elemento de um vetor em C++? * Exemplo #2 - erase(it) **********************************************/ #include <iostream> #include <vector> int main() { std::vector<int> intVector{10, 20, 30, 40, 50}; // endIt aponta para uma "casa" além do último elemento em intVector std::vector<int>::const_iterator endIt = intVector.end(); intVector.erase(endIt - 1); // Remove o valor 50 do vetor intVector.erase(endIt - 3); // Remove o valor 30 do vetor for (const int intValue : intVector) { std::cout << intValue << " "; } return 0; }
Note que no exemplo acima eu armazenei o retorno do método end()
aplicado ao intVector
em um iterador chamado endIt
. Todavia, isso não é recomendável quando se está removendo (ou adicionando) elementos a um vetor, pois durante essas operações o vetor pode ser redimensionado para expandir a sua memória que lhe é dedicada, ou para reduzí-la (caso tenham sido removidos elementos do vetor). Assim sendo, um iterador como endIt
que aponta para um endereço de memória de antes do redimensionamento do vetor, pode se tornar inválido após o redimensionamento. Isso nos leva ao quadro de boas práticas de programação a seguir.
Não armazene o retorno de end() se for adicionar ou remover elementos em um vetor
Armazenar o valor retornado por end() em um iterador quando se pretende adicionar ou remove elementos em um vetor pode causar erros difíceis de se detectar, pois o vetor pode ser redimensionado após as operações, e o iterador armazenado pode se tornar inválido. Ao invés disso, nesses casos é melhor usar a função end() no vetor diretamente, sempre que for necessário obter um iterador para além do fim do vetor.
Método #3 – erase(begIt, endIt)
A segunda sobrecarga do método erase é a que recebe dois iteradores, erase(begIt, endIt)
: um aponta para o início da faixa de valores que se deseja remover (begIt), e o outro aponta para exatamente um endereço de memória além do último elemento que se deseja remover (endIt) – os elementos removidos pertencem ao intervalo [begIt, endIt). Dessa forma, podemos remover vários elementos de um vetor de uma só vez. No exemplo #3 os elementos 20, 30 e 40 são removidos do vetor intVector
usando essa sobrecarga do método erase.
/********************************************** * Como remover um elemento de um vetor em C++? * Exemplo #3 - erase(begIt, endIt) **********************************************/ #include <iostream> #include <vector> int main() { std::vector<int> intVector{10, 20, 30, 40, 50}; // Remoção dos elementos 20, 30 e 40 do vetor intVector.erase(intVector.cbegin() + 1, intVector.cend() - 1); for (const int intValue : intVector) { std::cout << intValue << " "; } return 0; }
Remoção/adição no meio de um vetor
Adicionar ou remover um elemento de um vetor em C++ em um lugar que não seja o fim do contêiner é uma operação custosa (ou possivelmente muito custosa), pois requer o deslocamento dos outros elementos que se seguem àquele que foi adicionado ou removido, e pode exigir também um redimensionamento do vetor. Por esta razão, é recomendado que se utilize vetores (do tipo vector) apenas quando se deseja remover/adicionar elementos ao final da sequência. Nos outros casos, pode-se usar deque ou list, por exemplo.
Método #4 – remove(begIt, endIt, value)
Uma outra forma de se remover um elemento de um vetor em C++ é utilizar o método remove da biblioteca padrão (std). O remove pertence aos algorítmos genéricos que podem ser aplicados à maioria dos tipos de contêineres da biblioteca padrão, e ele permite remover todos os elementos de um vetor que pertenca a um intervalo (determinado por [begIt, endIt) ) e que possua o valor value. Vejamos a seguir um exemplo de uso do remove para remover todos os l (L minúsculo) de uma string.
Contudo, note que o remove funciona deslocando os elementos a serem removidos para o final da sequência, e retornando um iterador para o fim da nova sequência (sem os elementos deslocados); por essa razão, portanto, é que precisei remover os elementos do string usando o método erase (que vimos no método #3, e quem remove de fato os elementos), passando como argumento esse iterador para o novo fim do string, e end(), que aponta para o fim original da sequência.
/********************************************** * Como remover um elemento de um vetor em C++? * Exemplo #4 - remove(begIt, endIt, value) + erase() **********************************************/ #include <iostream> #include <string> #include <algorithm> int main() { std::string helloWorld{"Hello world!"}; // Remoção de todos os L minúsculos da string helloWorld.erase(std::remove(helloWorld.begin(), helloWorld.end(), 'l'), helloWorld.end()); std::cout << helloWorld << std::endl; return 0; }
Método #5 – remove_if(begIt, endIt, predicate)
O método remove possui ainda um parente que recebe como terceiro argumento um predicate para decidir quais elementos devem ser removidos do vetor, o remove_if. Um predicate é uma expressão que pode ser invocada e que retorna um valor verdadeiro ou falso. Logo, ao invés de remover elementos do vetor que são iguais a um valor dado, essa versão do remove elimina do vetor os elementos para os quais o predicate retorna true. O exemplo #5 mostra um exemplo de utilização do remove_if para remover todos os valores negativos de um vetor de inteiros.
/********************************************************** * Como remover um elemento de um vetor em C++? * Exemplo #5 - remove_if(begIt, endIt, predicate) + erase() ***********************************************************/ #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> intVector{1, -3, 4, 5, -10, 20, 32, -50}; // Remoção de todos os valores negativos de intVector intVector.erase(std::remove_if(intVector.begin(), intVector.end(), [](const int iValue) {return iValue < 0;}), intVector.end()); for (const auto aInt : intVector) { std::cout << aInt << " "; } return 0; }
Método #6 (bônus) – clear()
Esse último método não serve para remover um elemento de um vetor em C++ (ao menos não só um), mas sim para remover todos os elementos de um vetor qualquer. A seguir vemos um exemplo de sua utilização.
/********************************************** * Como remover um elemento de um vetor em C++? * Exemplo #6 - clear() **********************************************/ #include <iostream> #include <vector> int main() { std::vector<int> intVector{1, -3, 4, 5, -10, 20, 32, -50}; // Remoção de todos os valores do vetor intVector.clear(); if (intVector.empty()) { std::cout << "O vetor está vazio." << std::endl; } return 0; }
Conclusão
Neste artigo vimos 6 métodos para se remover um elemento de um vetor em C++. Começamos com o método mais simples, que permite apenas remover o último elemento do vetor: pop_back(). Em seguida, vimos os métodos para se remover um elemento qualquer de um vetor (ou um intervalo de elementos determinado por dois iteradores): erase(it), erase(begIt, endIt). Também foram abordados os métodos remove(begIt, endIt, value) e remove_if(begIt, endIt, predicate), que permitem remover todos os elementos de um vetor cujo valor seja igual a um valor passado como argumento (value), ou aqueles elementos para os quais o predicate (predicate) retorne true. Por fim, vimos ainda um método bônus – clear() – que permite remover todos os elementos presentes em um vetor.
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.