2016-05-05 17 views
5

C'è qualche motivo per operator[] di per restituire un riferimento invece di inserire un nuovo elemento? La pagina di cppreference.com per vector::operator dice herePerché non è implementato vector :: operator [] simile a map :: operator []?

differenza std::map::operator[], questo operatore non inserisce un nuovo elemento nel contenitore.

Mentre la pagina per map::operator[]says

"Restituisce un riferimento al valore mappato a un equivalente chiave a chiave, eseguendo un inserimento se tale chiave non esiste."

Perché non vector::operator[] potrebbero essere attuate chiamando vector::push_back o vector::insert come come map::operator[] chiamate insert(std::make_pair(key, T())).first->second;?

+3

Il modo in cui 'std :: map :: operator []' è effettivamente implementato causa già abbastanza confusione. UB va bene per 'std :: vector' accede ai limiti. –

+0

Immaginate cosa succederebbe se scrivessimo 'some_vector [1000]' mentre 'some_vector' fosse della dimensione 10. Beh, non so cosa immaginare con le 990 voci nel mezzo. –

+0

@NickyC: Ma una mappa ha lo stesso problema! –

risposta

7

Molto semplicemente: perché non ha senso. Che cosa ti aspetti

std::vector<int> a = {1, 2, 3}; 
a[10] = 4; 

da fare? Crea un quarto elemento anche se hai specificato l'indice 10? Crea elementi da 3 a 10 e restituisci un riferimento all'ultimo? Né sarebbe particolarmente intuitivo.

Se si desidera riempire un vettore con valori utilizzando operator[] anziché push_back, è possibile chiamare il vettore resize per creare gli elementi prima di impostarli.

Modifica: Oppure, se si desidera effettivamente disporre di un contenitore associativo, in cui l'indice è importante a parte l'ordine, std::map<int, YourData> potrebbe effettivamente avere più senso.

+2

Potrebbe valere la pena sottolineare il punto cruciale: per 'map', l'operatore inserisce al massimo un elemento alla chiave specificata. Per 'vector', dovresti anche inserire * altri * elementi in altri indici. –

+0

+1. Vale anche la pena ricordare che C++ considera le prestazioni più di molte delle lingue (ad es. Java). Questo è il motivo per cui 'vector :: operator []' non esegue il controllo dei limiti; puoi accedervi manualmente se ritieni di averne bisogno, ma il C++ non vuole avere un sovraccarico qui. Anche se l'inserimento di elementi inesistenti in un vettore aveva senso, sarebbe in contraddizione con gli obiettivi di performance piuttosto direttamente. Come nel caso del desiderio di controllo dei limiti, se desideri inserire elementi per te, puoi costruire una classe di livello superiore oltre al vettore te stesso e opt-in. – GManNickG

+0

@GManNickG Quindi, in pratica, se desidero inserire elementi inesistenti, sono costretto a utilizzare una mappa perché il vettore è un contenitore di sequenze? – 1337ninja

1

Una mappa e un vettore sono concetti completamente diversi. Una mappa è un "contenitore associativo" mentre un vettore è un "contenitore di sequenza". Delineare le differenze è fuori dallo scopo di questa risposta, anche se ai livelli più superficiali, una mappa viene generalmente implementata come un albero rosso-nero, mentre un vettore è un involucro involuto su un array in stile C (elementi memorizzati in modo contiguo in memoria).

Se si desidera verificare se un elemento esiste già, è necessario ridimensionare l'intero contenitore. Ma cosa succede se decidi di rimuovere l'elemento? Cosa fai con le voci che hai appena creato? Con una mappa:

std::map<int, int> m; 
m[1] = 1; 
m.erase(m.begin()); 

Questa è un'operazione costante.

Con un vettore:

std::vector<int> v; 
// ... initialize some values between 25 and 100 
v[100] = 1; 
v.erase(v.begin() + 25, v.end()); 

Questo è un funzionamento lineare. Questo è orribilmente inefficiente (comparativamente) in una mappa. Mentre questo è un esempio forzato, non è difficile immaginare come questo potrebbe esplodere in altri scenari. Come minimo, la maggior parte delle persone farebbe di tutto per evitare operator[] che come un costo in sé (manutenzione e complessità del codice).

+0

+1 perché hai toccato il fatto che i vettori e i puntatori sono basati su due strutture dati separate. I vettori sono array piuttosto fantasiosi, mentre le mappe sono basate su puntatori. Le mappe sono grandi se devi usare gli iteratori per cercare. Mentre i Vettori sono fantastici se si conosce quale elemento è necessario nella matrice. – Caperneoignis

0

C'è qualche ragione per l'operatore std :: vector [] per restituire un riferimento invece di inserire un nuovo elemento?

std::vector::operator[] è implementato in un modo simile matrice perché std::vector è un contenitore di sequenza (cioè, array simili). Non è possibile accedere agli array standard per i tipi interi senza limiti. Analogamente, l'accesso a std::vector::operator[] con un indice esterno alla lunghezza del vettore non è consentito neanche. Quindi, sì, i motivi per cui non è implementato come chiedete è perché in nessun altro contesto, gli array in C++ agiscono in questo modo.

std::map::operator[] non è un contenitore di sequenza. La sua sintassi lo rende simile agli array associativi in ​​altre lingue. In termini di C++ (e del suo predecessore, C), lo map::operator[] è solo zucchero sintattico. È la "pecora nera" della famiglia operator[], nonstd::vector::operator[].

La parte interessante della specifica C++ riguardante è che l'accesso a una mappa con una chiave che non esiste, utilizzando std::map::operator[], aggiunge un elemento alla mappa. Così,

#include <iostream> 
#include <map> 
int main(void) { 
    std::map<char, int> m; 
    m['a'] = 1; 
    std::cout << "m['a'] == " << m['a'] << ", m.size() == " << m.size() << std::endl; 
    std::cout << "m['b'] == " << m['b'] << ", m.size() == " << m.size() << std::endl; 
} 

risultati in:

m['a'] == 1, m.size() == 1 
m['b'] == 0, m.size() == 2 

Vedi anche: Difference between map[] and map.at in C++?:

[map::at] genera un'eccezione se la chiave non esiste, restituisce findaMap.end() se l'elemento non esiste e il valore operator[]inizializza un nuovo valore per la chiave corrispondente se non v alue esiste lì.