2008-11-04 7 views
85

Der folgende Code besagt, dass die Karte als const in die operator[] Methode übergeben verwirft Qualifier:C++ Karte Zugang verwirft Qualifier (const)

#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; 
} 

Ist dies wegen der möglichen Zuordnung, die auf der Karte Zugriff auftritt? Können keine Funktionen mit Map-Zugriffen als const deklariert werden?

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

+0

Nur nitpick, aber mw kann einfach als MapWrapper deklariert werden MW; – luke

+0

Guter Punkt - Ich schreibe in ein paar Sprachen, deshalb tendiere ich dazu, die Syntax zu normalisieren, so dass sie alle in meinen Kopf passen. :) – cdleary

+0

Ich kann das schätzen. Seien Sie vorsichtig, in Fällen wie diesem haben Sie eine zusätzliche Objektkonstruktion und Zuweisung, die nicht notwendig sind. – luke

Antwort

118

std::map's operator [] is not declared as const, and cannot be due to its behavior:

T & Operator [] (const Key & key)

Gibt einen Verweis auf den Wert, der mit einem Schlüssel entspricht Schlüssel zugeordnet wird, Einfügung durchführt, wenn eine solche Taste nicht bereits existieren.

Als Ergebnis können Sie Ihre Funktion nicht const deklariert werden, und die Karte des verwenden operator[].

std::map's find() Funktion ermöglicht es Ihnen, einen Schlüssel nachschlagen, ohne die Karte zu ändern.

find() Gibt eine iterator oder const_iterator zu einem std::pair sowohl den Schlüssel (.first) und den Wert enthält (.second).

In C++ 11 können Sie auch at() für std::map verwenden. Wenn das Element nicht existiert, löst die Funktion eine std::out_of_range Ausnahme aus, im Gegensatz zu operator [].

+6

zusätzlich: VALUE = map.find (KEY) -> Sekunde; Ich musste lernen, dass 'find()' einen Iterator vom Typ pair zurückgibt. – FlipMcF

+4

Ich würde hinzufügen, dass jetzt in C11 Sie verwenden können: std :: map :: at (Schlüssel) und vermeiden Sie den Iterator. –

+2

Interessant. Ich würde denken, C++ würde zwischen lvalue 'operator []' (z. B. 'foo [bar] = baz') und rvalue' operator [] '(z. B.' x = foo [bar] ') unterscheiden - letzteres könnte sicherlich const sein. – Claudiu

10

Sie nicht Operator [] auf einer Karte verwenden können, die const als diese Methode ist nicht const, da es Sie die Karte ändern können (Sie können zuweisen [key] _MAP). Versuchen Sie stattdessen, die find-Methode zu verwenden.

+1

Zur Erklärung: Was sollte map's operator [] tun, wenn der Schlüssel nicht existiert? Wenn die Zuordnung nicht konstant ist, wird der Schlüssel mit dem standardmäßig konstruierten Wert hinzugefügt. Wenn die Map const ist, was kann von operator [] zurückgegeben werden? Es gibt keinen Wert für diesen Schlüssel. – Arkadiy

7

Einige neuere Versionen der GCC-Header (4.1 und 4.2 auf meinem Rechner) haben nicht standardmäßige Memberfunktionen map :: at(), die const deklariert werden und std :: out_of_range werfen, wenn der Schlüssel nicht in der Map ist.

const mapped_type& at(const key_type& __k) const 

Von einer Referenz in der Bemerkung der Funktion scheint es, dass dies als eine neue Member-Funktion in der Standardbibliothek vorgeschlagen wurde.

+0

Ich denke, das ist eine kleine Eigenart. Die at-Funktion ist Teil des kommenden Standards, aber ich finde kein at() in der aktuellen. –

+0

Einen Fehlerbericht archiviert: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46544 –

+0

'at' ist Teil von C++ 11. –

0

Zuerst sollten Sie keine Symbole verwenden, die mit _ beginnen, da sie für die Sprachimplementierung/den Compilerschreiber reserviert sind. Es wäre sehr einfach für _map, ein Syntaxfehler auf jemandes Compiler zu sein, und Sie hätten niemand außer sich selbst zu beschuldigen.

Wenn Sie einen Unterstrich verwenden möchten, setzen Sie ihn am Ende, nicht am Anfang. Sie haben wahrscheinlich diesen Fehler gemacht, weil Sie einen Microsoft-Code gesehen haben. Denken Sie daran, sie schreiben ihren eigenen Compiler, damit sie damit durchkommen können. Trotzdem ist es eine schlechte Idee.

Der Operator [] gibt nicht nur eine Referenz zurück, sondern erstellt auch den Eintrag in der Karte. So erhalten Sie nicht nur eine Zuordnung, wenn es keine gibt, erstellen Sie eine. Das haben Sie nicht beabsichtigt.

+4

Ihr Punkt über '_' ist einfach falsch. Bezeichner, die mit zwei Unterstrichen beginnen ('__Beispiel ') oder Bezeichner, die einen Unterstrich und einen Großbuchstaben (' _Beispiel') beginnen, sind reserviert. '_example' ist nicht reserviert. – Ethan

9

Da operator[] keine Const-qualifizierte Überlast hat, kann sie nicht sicher in einer const-qualifizierten Funktion verwendet werden.Dies liegt wahrscheinlich daran, dass die aktuelle Überlastung mit dem Ziel erstellt wurde, Schlüsselwerte zurückzugeben und zu setzen.

Stattdessen können Sie verwenden:

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

oder in C++ 11, können Sie den at() Operator verwenden:

VALUE = map.at(KEY);