HOWTO · C++

Remover Elemento de Vector em C++

Este artigo demonstra como remover um elemento do vector em C++

Nesta página

Para remover uma posição ou um intervalo conhecido, use std::vector::erase. Para remover todos os elementos iguais a um valor em C++20, use std::erase; em versões anteriores do C++, combine std::remove e erase com o idioma erase-remove. Os exemplos mostram como cada opção altera o vetor e como manter os iteradores válidos.

Remover um elemento com std::vector::erase

std::vector::erase aceita um iterador para um elemento ou um intervalo semiaberto [first, last). O intervalo inclui first e exclui last. A sobrecarga para um único elemento exige um iterador válido que aponte para um elemento. Retorna um iterador para o elemento seguinte ao intervalo removido ou end() se não houver elemento seguinte.

Este exemplo completo remove o elemento no índice 2 e, em seguida, lê o iterador devolvido:

Execute este exemplo:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers{10, 20, 30, 40, 50};
    auto next = numbers.erase(numbers.begin() + 2);

    for (std::size_t i = 0; i < numbers.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << numbers[i];
    }
    std::cout << "\nNext value: " << *next << '\n';
}
10 20 40 50
Next value: 40

A remoção invalida os iteradores e as referências na posição removida e depois dela. Atualize ou descarte esses identificadores antes de os voltar a usar. Para remover um intervalo, passe o iterador para o primeiro elemento e o iterador para a posição imediatamente após o último; o iterador devolvido e as regras de invalidação são os mesmos. Se o intervalo removido chegar ao fim, o iterador devolvido será igual a numbers.end() e não poderá ser desreferenciado.

Remover todos os valores correspondentes com std::erase (C++20)

O C++20 acrescenta a sobrecarga não membro std::erase para std::vector, declarada através de <vector>. Remove todos os elementos iguais ao valor fornecido e devolve a quantidade removida. Se houver correspondências repetidas, remove-as todas; por isso, é útil quando a seleção se baseia na igualdade. As versões anteriores da linguagem não disponibilizam esta sobrecarga; nesse caso, use o idioma erase-remove apresentado na secção seguinte.

Este exemplo usa std::erase quando é compilado como C++20 e recorre ao idioma erase-remove com uma versão anterior. Ambos os ramos removem todas as ocorrências de 2 e apresentam a quantidade removida:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers{1, 2, 3, 2, 4, 2, 5};
    std::size_t removed;

#if __cplusplus >= 202002L
    removed = std::erase(numbers, 2);
#else
    const auto old_size = numbers.size();
    const auto new_end = std::remove(numbers.begin(), numbers.end(), 2);
    numbers.erase(new_end, numbers.end());
    removed = old_size - numbers.size();
#endif

    std::cout << "Removed: " << removed << "\nRemaining: ";
    for (std::size_t i = 0; i < numbers.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << numbers[i];
    }
    std::cout << '\n';
}
Removed: 3
Remaining: 1 3 4 5

A sobrecarga de std::erase para std::vector está disponível a partir do C++20 e devolve a quantidade removida. O ramo para versões anteriores usa o idioma erase-remove, explicado abaixo.

Remover valores correspondentes com o idioma erase-remove

Antes do C++20, combine std::remove de <algorithm> com a função membro erase do vetor. std::remove desloca os valores que não correspondem para o início do intervalo modificável e devolve um iterador para o novo fim lógico. Não altera o tamanho do vetor: este continua a conter o número original de elementos até que o intervalo final seja removido. Passe o iterador devolvido e o end() original do vetor a erase para reduzir o contentor.

Este exemplo remove todas as ocorrências de 2 com esse padrão de duas etapas:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers{1, 2, 3, 2, 4, 5};
    const auto new_end = std::remove(numbers.begin(), numbers.end(), 2);
    numbers.erase(new_end, numbers.end());

    for (std::size_t i = 0; i < numbers.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << numbers[i];
    }
    std::cout << '\n';
}

O intervalo passado a std::remove tem de ser modificável, porque o algoritmo reorganiza os valores que são mantidos. O acesso de leitura a um contentor através de iteradores constantes não impede o uso deste idioma quando está disponível um intervalo de iteradores modificáveis.

Remover elementos com segurança durante a iteração

Quando um predicado ou outra condição determina o que deve ser removido, use um ciclo com iterador. Depois de remover um elemento, atribua ao iterador o valor devolvido por erase; incremente-o apenas quando o elemento atual for mantido. O iterador do elemento removido fica inválido, por isso é inseguro incrementá-lo ou desreferenciá-lo.

Este exemplo remove os valores pares e mantém o iterador válido:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7};
    for (auto it = numbers.begin(); it != numbers.end();) {
        if (*it % 2 == 0) {
            it = numbers.erase(it);
        } else {
            ++it;
        }
    }

    for (std::size_t i = 0; i < numbers.size(); ++i) {
        if (i != 0) std::cout << ' ';
        std::cout << numbers[i];
    }
    std::cout << '\n';
}

Use std::erase para remover por igualdade em C++20, o idioma erase-remove para essa tarefa em versões anteriores e erase com um ciclo que usa o iterador devolvido quando a remoção depende de uma condição. A escolha adequada depende de a seleção ser uma posição ou um intervalo conhecido, a igualdade com um valor ou um predicado avaliado à medida que o ciclo avança.