Perché l'operatore [] const per le mappe STL?


89

Esempio artificioso, per il bene della domanda:

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

Non verrà compilato, poiché l'operatore [] non è const.

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

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?


5
Cosa dovrebbe operator[]produrre nel caso in cui l'elemento dato non esiste?
Frerich Raabe

4
@Frerich Raabe: La stessa cosa della funzione membro at: throw std :: out_of_range
Jean-Simon Brochu

Risposte:


90

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

Poiché deve essere consentito l'errore e inserire un valore predefinito, l'operatore non può essere utilizzato su constun'istanza del contenitore.

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


3
std::setnon ha operator[].
avakar

2
Questa è la risposta giusta, ma una versione const potrebbe fare la stessa cosa del membro "at". Ovvero lanciare uno std :: out_of_range ...
Jean-Simon Brochu

Quando viene utilizzato per leggere un valore, non è disponibile alcun valore predefinito. std::vectorha un operatore di lettura []che è const. mapdovrebbe fare lo stesso.
wcochran

51

Ora che con C ++ 11 puoi avere una versione più pulita usando at ()

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

4
Se maphanno const e non const at()s - perché non lo stesso anche per operator[]? con la versione const non si inserisce nulla ma piuttosto si lancia? (O restituendo un optional, quando std :: optional lo rende lo standard)
einpoklum

@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.
Millie Smith

@einpoklum Molto tardi, ma per altri lettori: avere due sovraccarichi che fanno cose così diverse sarebbe terribile. L'unico motivo è atdisponibile in due versioni è perché fa a return *this;, e l'unica differenza tra i sovraccarichi è la const-ità del riferimento restituito. Gli effetti effettivi di entrambi ati messaggi sono esattamente gli stessi (ovvero, nessun effetto).
HTNW

28

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

Va notato che esiste una versione const di operator [] sulla maggior parte dei contenitori.
È 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 tuo secondo esempio dovresti verificare la mancata ricerca dell'elemento.

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

1
std::setnon ha operator[]affatto.
Tutti

2

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)). Second. A rigor di termini, questa funzione membro non è necessaria: esiste solo per comodità


0

Un operatore di indice dovrebbe essere const solo per un contenitore di sola lettura (che non esiste realmente in STL di per sé).

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


6
La domanda è: perché non ha due versioni sovraccaricate - una const, un'altra non const- come ad esempio std::vector.
Pavel Minaev,

-2

Se dichiari che la tua variabile membro std :: map è modificabile

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

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


15
Questa è un'idea terribile, però.
GManNickG

7
L'API per la tua classe si trova se lo fai. La funzione afferma che è const, il che significa che non modificherà alcuna variabile membro, ma in realtà potrebbe modificare il membro dati m_map.
Runcible

2
mutablepuò essere usato per membri come std::mutex, cache e helper di debug. Se la mappa deve essere utilizzata come cache per velocizzare una constfunzione "getter" molto costosa , allora mutableè accettabile. Devi stare attento, ma di per sé non è un'idea terribile.
Mark Lakata
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.