cosa succede quando modifichi un elemento di uno std :: set?

Se cambio un elemento di un std :: set, ad esempio, attraverso un iteratore, so che non è “reinserito” o “ricorsa”, ma c’è qualche menzione se triggers un comportamento indefinito? Ad esempio, immagino che gli inserimenti rovinerebbero. C’è qualche menzione di ciò che accade specificamente?

Non modificare direttamente i valori memorizzati nel set. Ho copiato questo dalla documentazione MSDN che è alquanto autorevole:

Il set di classi del contenitore STL viene utilizzato per la memorizzazione e il recupero di dati da una raccolta in cui i valori degli elementi contenuti sono univoci e fungono da valori chiave in base ai quali i dati vengono ordinati automaticamente. Il valore di un elemento in un set non può essere modificato direttamente. Invece, è necessario eliminare vecchi valori e inserire elementi con nuovi valori.

Perché questo è abbastanza facile da capire. L’implementazione set non ha modo di sapere che hai modificato il valore dietro le sue spalle. L’implementazione normale è un albero rosso-nero. Avendo cambiato il valore, la posizione nell’albero per quell’istanza sarà errata. Ci si aspetterebbe di vedere tutti i tipi di comportamento errato, come le query exists restituiscono il risultato errato a causa della ricerca che scende lungo il ramo sbagliato dell’albero.

La risposta esatta dipende dalla piattaforma, ma come regola generale, una “chiave” (il materiale che inserisci in un set o il primo tipo di mappa) è supposta essere “immutabile”. Per dirla in parole semplici, non dovrebbe essere modificato, e non c’è nulla come il reinserimento automatico.

Più precisamente, le variabili membro utilizzate per confrontare la chiave non devono essere modificate.

Il compilatore Windows vc è abbastanza flessibile (testato con VC8) e questo codice viene compilato:

 // creation std::set toto; toto.insert(4); toto.insert(40); toto.insert(25); // bad modif (*toto.begin())=100; // output for(std::set::iterator it = toto.begin(); it != toto.end(); ++it) { std::cout<<*it<<" "; } std::cout< 

L'output è 100 25 40 , che ovviamente non è ordinato ... Cattivo ... Tuttavia, tale comportamento è utile quando si desidera modificare i dati che non partecipano all'operatore < . Ma è meglio sapere cosa stai facendo: questo è il prezzo che ottieni per essere troppo flessibile.

Alcuni potrebbero preferire il comportamento di gcc (testato con 3.4.4) che dà l'errore "assegnazione del percorso di sola lettura". Puoi aggirarlo con un const_cast:

 const_cast(*toto.begin())=100; 

Ora si sta compilando anche su gcc, stesso risultato: 100 25 40 . Ma almeno, così facendo probabilmente ti chiedi cosa sta succedendo, poi vai a stack overflow e guarda questo thread 🙂

Non puoi farlo; sono const . Non esiste alcun metodo con cui il set possa rilevare che si sta apportando una modifica all’elemento interno e, di conseguenza, non è ansible farlo. Invece, devi rimuovere e reinserire l’elemento. Se si utilizzano elementi che sono costosi da copiare, potrebbe essere necessario passare a utilizzare puntatori e comparatori personalizzati (o passare a un compilatore C ++ 1x che supporti i riferimenti rvalue, il che renderebbe le cose molto più belle).