C ++ map access scarta qualificatori (const)


113

Il codice seguente dice che passando la mappa come constnel operator[]metodo scarta i qualificatori:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

È a causa della possibile assegnazione che si verifica sull'accesso alla mappa? Nessuna funzione con accessi alla mappa può essere dichiarata const?

MapWrapper.cpp:10: error: passing ‘const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >]’ discards qualifiers


Solo un pignolo, ma mw può essere dichiarato semplicemente come MapWrapper mw;
Luca

Buon punto: scrivo in un paio di lingue, quindi tendo a normalizzare la sintassi tra loro in modo che si adattino tutte alla mia testa. :)
cdleary

Lo posso apprezzare. Fai attenzione però, in casi come questo hai una costruzione e un incarico di oggetti extra che non sono necessari.
Luca

Un altro buon punto: fare affidamento sull'operatore di assegnazione predefinito non è una buona pratica per esempi pubblici. ;)
cdleary

Risposte:


152

std::map's operator []non è dichiarato come const, e non può essere dovuto al suo comportamento:

T & operator [] (const Key & key)

Restituisce un riferimento al valore che è mappato a una chiave equivalente alla chiave, eseguendo l'inserimento se tale chiave non esiste già.

Di conseguenza, la tua funzione non può essere dichiarata conste usa quella della mappa operator[].

std::mapLafind() funzione di consente di cercare una chiave senza modificare la mappa.

find()restituisce un iterator, o const_iteratora un std::paircontenente sia la chiave ( .first) che il valore ( .second).

In C ++ 11, potresti anche usare at()per std::map. Se l'elemento non esiste, la funzione genera std::out_of_rangeun'eccezione, al contrario di operator [].


8
inoltre: VALUE = map.find (KEY) -> second; Ho dovuto imparare che 'find ()' restituisce un iteratore, che è di tipo coppia.
FlipMcF

5
Vorrei aggiungere che ora in C11 puoi usare: std :: map :: at (key) ed evitare l'iteratore.
Juan Besa

3
Interessante. Penso che C ++ distinguerebbe tra lvalue operator[](eg foo[bar] = baz) e rvalue operator[](eg x = foo[bar]) - quest'ultimo potrebbe certamente essere const.
Claudiu

15

Poiché operator[]non dispone di un overload qualificato const, non può essere utilizzato in modo sicuro in una funzione qualificata const. Ciò è probabilmente dovuto al fatto che il sovraccarico corrente è stato creato con l'obiettivo di restituire e impostare valori chiave.

Puoi invece usare:

VALUE = map.find(KEY)->second;

oppure, in C ++ 11, puoi usare l' at()operatore:

VALUE = map.at(KEY);

map.find(KEY)->second; non è sicuro quando i valori della mappa sono stringhe. Tende a stampare spazzatura quando la CHIAVE non viene trovata.
Syam

1
Questa è una risposta adeguatamente spiegata che va al punto. Ieri ho passato 2 ore cercando di capire cosa stesse succedendo con un caso simile. Possiamo essere d'accordo che il messaggio di errore è, nella migliore delle ipotesi, fuorviante? Potrei essere molto più chiaro se non avesse la parola "questo" e facesse riferimento a const-ness invece del qualificatore più generico .
carnicer

11

Non è possibile utilizzare operator[]su una mappa in constquanto tale metodo non lo è constin quanto consente di modificare la mappa (è possibile assegnarla a _map[key]). Prova invece a usare il findmetodo.


1
A titolo di spiegazione: cosa dovrebbe fare l'operatore della mappa [] se la chiave non esiste? Se la mappa non è const, la chiave viene aggiunta con un valore costruito per impostazione predefinita. Se la mappa const, cosa può essere restituito dall'operatore []? Non c'è alcun valore in quella chiave.

Questa è una risposta adeguatamente spiegata che va al punto. Ieri ho passato 2 ore cercando di capire cosa stesse succedendo con un caso simile. Possiamo essere d'accordo che il messaggio di errore è, nella migliore delle ipotesi, fuorviante? Potrei essere molto più chiaro se non avesse la parola "questo" e facesse riferimento a const-ness invece del qualificatore più generico .
carnicer

7

Alcune versioni più recenti delle intestazioni GCC (4.1 e 4.2 sulla mia macchina) hanno funzioni membro non standard map :: at () che sono dichiarate const e lanciano std :: out_of_range se la chiave non è nella mappa.

const mapped_type& at(const key_type& __k) const

Da un riferimento nel commento della funzione, sembra che questo sia stato suggerito come una nuova funzione membro nella libreria standard.


Immagino sia un piccolo capriccio. La funzione at fa parte dello standard imminente, ma non trovo at () in quello corrente.
Sebastian Mach

'at' fa parte di C ++ 11.
Étienne

0

Primo, non dovresti usare simboli che iniziano con _ perché sono riservati all'implementazione del linguaggio / autore del compilatore. Sarebbe molto facile per _map essere un errore di sintassi sul compilatore di qualcuno e non avresti nessuno da incolpare tranne te stesso.

Se vuoi usare un trattino basso, mettilo alla fine, non all'inizio. Probabilmente hai commesso questo errore perché hai visto del codice Microsoft farlo. Ricorda, scrivono il loro compilatore, quindi potrebbero essere in grado di farla franca. Anche così, è una cattiva idea.

l'operatore [] non solo restituisce un riferimento, ma crea effettivamente la voce nella mappa. Quindi non stai solo ottenendo una mappatura, se non ce n'è, ne stai creando una. Non è quello che volevi.


5
Il tuo punto di vista _è semplicemente sbagliato. Gli identificatori che iniziano con due trattini bassi ( __example) o gli identificatori che iniziano con un trattino basso e una lettera maiuscola ( _Example) sono riservati. _examplenon è riservato.
Ethan
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.