2009-09-25 13 views
70

esempio forzato, per motivi di domanda:Perché non l'operatore [] const per le mappe STL?

void MyClass::MyFunction(int x) const 
{ 
    std::cout << m_map[x] << std::endl 
} 

Questo non verrà compilato, in quanto l'operatore [] è non-const.

Questo è un peccato, poiché la sintassi [] sembra molto pulita. Invece, devo fare qualcosa di simile:

void MyClass::MyFunction(int x) const 
{ 
    MyMap iter = m_map.find(x); 
    std::cout << iter->second << std::endl 
} 

Questo mi ha sempre infastidito. Perché l'operatore [] non-const?

+4

Quale dovrebbe essere 'operatore []' resa in caso l'elemento dato non esiste? –

+1

@Frerich Raabe: La stessa cosa della funzione membro at: throw std :: out_of_range –

risposta

76

Per std::map, operator[] inserirà il valore di indice nel contenitore se prima non esisteva. È un po 'non intuitivo, ma è così.

Poiché è necessario consentire il failover e inserire un valore predefinito, l'operatore non può essere utilizzato su un'istanza const del contenitore.

http://en.cppreference.com/w/cpp/container/map/operator_at

+1

'std :: set' non ha 'operator []'. – avakar

+0

Oops, giusto. Modificato. – Alan

+0

Questa è la risposta giusta, ma una versione const potrebbe fare la stessa cosa del membro "at". Questo è gettare uno std :: out_of_range ... –

0

Un operatore di indice deve essere solo const per un contenitore di sola lettura (che in realtà non esiste in AWL di per sé).

Gli operatori di indice non sono utilizzati solo per esaminare i valori.

+4

La domanda è, perché non ha due versioni sovraccaricate - una 'const', un'altra non-'const' - come ad es. 'std :: vector' fa. –

26

Nota per i nuovi lettori.
La domanda originale riguardava i contenitori STL (non specificamente per la std :: map)

Si noti che sulla maggior parte dei contenitori è presente una versione const dell'operatore [].
È solo che std :: map e std :: set non hanno una versione const e questo è il risultato della struttura sottostante che li implementa.

Da std :: vector

reference  operator[](size_type n) 
const_reference operator[](size_type n) const 

anche per il secondo esempio si dovrebbe verificare la presenza di un fallimento di trovare l'elemento.

void MyClass::MyFunction(int x) const 
{ 
    MyMap iter = m_map.find(x); 
    if (iter != m_map.end()) 
    { 
     std::cout << iter->second << std::endl 
    } 
} 
+0

'std :: set' non ha affatto 'operator []'. – Everyone

0

Se si dichiara la variabile membro std :: map essere mutabile

mutable std::map<...> m_map; 

è possibile utilizzare le funzioni di membro non-const di std :: map all'interno delle vostre funzioni membro const.

+13

Questa è una pessima idea, però. – GManNickG

+0

Perché questa è una pessima idea? –

+6

L'API per la tua classe giace se lo fai. La funzione afferma che è const - ovvero che non modificherà alcuna variabile membro - ma in realtà potrebbe modificare il membro dei dati m_map. – Runcible

3

Poiché operator [] potrebbe inserire un nuovo elemento nel contenitore, non può essere una funzione membro const. Si noti che la definizione di operatore [] è estremamente semplice: m [k] è equivalente a (* ((m.insert (value_type (k, data_type()))) first)). A rigor di termini, questa funzione membro è inutile: esiste solo per comodità

41

Ora che con C++ 11 si può avere una versione più pulita utilizzando at()

void MyClass::MyFunction(int x) const 
{ 
    std::cout << m_map.at(x) << std::endl; 
} 
+3

Se 'map' ha const e non-const' a() 's - perché non lo stesso anche per' operator [] '? con la versione const non si inserisce nulla ma piuttosto si lancia? (Oppure restituendo un optional, quando std :: facoltativo lo rende nello standard) – einpoklum

+0

@einpoklum Il punto di correttezza const è principalmente il controllo statico in fase di compilazione. Preferirei che il compilatore si lamentasse piuttosto che lanciare un'eccezione perché non ho usato correttamente gli oggetti const. –

Problemi correlati