HOWTO · C++
Rimuovi elemento dal vettore in C++
Questo articolo mostra come rimuovere un elemento dal vettore in C++
In questa pagina
Per rimuovere una posizione o un intervallo specifico, usa std::vector::erase. Per rimuovere in C++20 tutti gli elementi uguali a un valore, usa std::erase; con gli standard C++ precedenti, combina std::remove e erase secondo l’idioma erase-remove. Gli esempi mostrano come ciascuna scelta modifica il vettore e come mantenere validi gli iteratori.
Rimuovere un elemento con std::vector::erase
std::vector::erase accetta un iteratore a un singolo elemento oppure un intervallo semiaperto [first, last). L’intervallo include first ed esclude last. L’overload per un singolo elemento richiede un iteratore valido che punti a un elemento. Restituisce un iteratore all’elemento successivo all’intervallo cancellato oppure end() se non ci sono elementi successivi.
Questo esempio completo rimuove l’elemento all’indice 2 e poi legge l’iteratore restituito:
Esegui questo esempio:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#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
La cancellazione invalida gli iteratori e i riferimenti che si trovano in corrispondenza della posizione cancellata o dopo di essa. Aggiorna o scarta questi riferimenti prima di riutilizzarli. Per cancellare un intervallo, passa l’iteratore al suo primo elemento e quello che punta all’elemento successivo all’ultimo; l’iteratore restituito e le regole di invalidazione sono gli stessi. Se l’intervallo cancellato arriva alla fine, l’iteratore restituito coincide con numbers.end() e non può essere dereferenziato.
Rimuovere tutti i valori corrispondenti con std::erase (C++20)
C++20 aggiunge l’overload non membro std::erase per std::vector, dichiarato tramite <vector>. Rimuove tutti gli elementi uguali al valore fornito e restituisce il numero di elementi rimossi. Rimuove anche le occorrenze ripetute, quindi è utile quando la selezione si basa sull’uguaglianza. Gli standard precedenti non forniscono questo overload; usa l’idioma erase-remove descritto nella sezione successiva.
Questo esempio usa std::erase quando viene compilato come C++20 e ricorre all’idioma erase-remove con uno standard precedente. Entrambi i rami rimuovono tutte le occorrenze di 2 e stampano il numero di elementi rimossi:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#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
L’overload di std::erase per std::vector è disponibile a partire da C++20 e restituisce il numero di elementi rimossi. Il ramo per gli standard precedenti usa l’idioma erase-remove, spiegato qui sotto.
Rimuovere i valori corrispondenti con l’idioma erase-remove
Prima di C++20, combina std::remove di <algorithm> con il metodo membro erase del vettore. std::remove sposta i valori non corrispondenti verso l’inizio dell’intervallo scrivibile e restituisce un iteratore alla nuova fine logica. Non modifica la dimensione del vettore: finché non viene cancellato l’intervallo finale, il vettore contiene ancora lo stesso numero di elementi. Passa a erase l’iteratore restituito e l’end() originale del vettore per ridurre la dimensione del contenitore.
Questo esempio rimuove tutte le occorrenze di 2 con questa procedura in due passaggi:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#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';
}
L’intervallo passato a std::remove deve essere scrivibile, perché l’algoritmo riordina i valori conservati. L’accesso in sola lettura a un contenitore tramite iteratori const non impedisce di usare questo idioma, purché sia disponibile un intervallo di iteratori scrivibile.
Cancellare elementi in sicurezza durante l’iterazione
Quando è una condizione o un predicato a determinare quali elementi rimuovere, usa un ciclo con iteratore. Dopo la cancellazione, assegna all’iteratore quello restituito da erase; incrementalo solo se l’elemento corrente rimane. L’iteratore cancellato non è più valido: incrementarlo o dereferenziarlo è quindi rischioso.
Questo esempio rimuove i valori pari mantenendo valido l’iteratore:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#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';
}
In C++20 usa std::erase per rimuovere in base all’uguaglianza; con gli standard precedenti, usa l’idioma erase-remove per lo stesso scopo. Se invece la rimozione dipende da una condizione, usa erase in un ciclo e aggiorna l’iteratore con quello restituito. La scelta dipende dal fatto che la selezione riguardi una posizione o un intervallo specifico, l’uguaglianza con un valore oppure un predicato valutato durante l’iterazione.