Gibt es eine Möglichkeit , den Standardwert angeben std::map
‚s operator[]
zurückgibt , wenn ein Schlüssel nicht existiert?
85
Nein, gibt es nicht. Die einfachste Lösung besteht darin, eine eigene kostenlose Vorlagenfunktion zu schreiben, um dies zu tun. Etwas wie:
#include <string>
#include <map>
using namespace std;
template <typename K, typename V>
V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval ) {
typename std::map<K,V>::const_iterator it = m.find( key );
if ( it == m.end() ) {
return defval;
}
else {
return it->second;
}
}
int main() {
map <string,int> x;
...
int i = GetWithDef( x, string("foo"), 42 );
}
C ++ 11 Update
Zweck: Berücksichtigen Sie generische assoziative Container sowie optionale Komparator- und Allokatorparameter.
template <template<class,class,class...> class C, typename K, typename V, typename... Args>
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval)
{
typename C<K,V,Args...>::const_iterator it = m.find( key );
if (it == m.end())
return defval;
return it->second;
}
operator[]
mit dem Standardwert bereitzustellen , sollte der Standardwert in die Karte innerhalb desif ( it == m.end() )
Blocks eingefügt werdenDies beantwortet zwar nicht genau die Frage, aber ich habe das Problem mit Code wie diesem umgangen:
quelle
Der C ++ - Standard (23.3.1.2) gibt an, dass der neu eingefügte Wert standardmäßig erstellt wird, sodass er
map
selbst keine Möglichkeit bietet, dies zu tun. Sie haben folgende Möglichkeiten:operator[]
, um diesen Standard einzufügen.quelle
Allgemeinere Version, Unterstützung von C ++ 98/03 und mehr Containern
Funktioniert mit generischen assoziativen Containern. Der einzige Vorlagenparameter ist der Containertyp selbst.
Unterstützte Behälter:
std::map
,std::multimap
,std::unordered_map
,std::unordered_multimap
,wxHashMap
,QMap
,QMultiMap
,QHash
,QMultiHash
, usw.Verwendung:
Hier ist eine ähnliche Implementierung unter Verwendung einer Wrapper-Klasse, die
get()
derdict
Typmethode in Python ähnlicher ist : https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hppVerwendung:
quelle
C ++ 17 bietet
try_emplace
genau das. Es nimmt einen Schlüssel und eine Argumentliste für den Wertekonstruktor und gibt ein Paar zurück: aniterator
und abool
.: Http://en.cppreference.com/w/cpp/container/map/try_emplacequelle
Es gibt keine Möglichkeit, den Standardwert anzugeben - es handelt sich immer um einen vom Standard (Nullparameter-Konstruktor) erstellten Wert.
Tatsächlich macht es
operator[]
wahrscheinlich mehr als Sie erwarten, als ob ein Wert für den angegebenen Schlüssel in der Zuordnung nicht existiert. Es wird ein neuer mit dem Wert aus dem Standardkonstruktor eingefügt.quelle
find
die den Enditerator zurückgeben, wenn für einen bestimmten Schlüssel kein Element vorhanden ist.find
in diesem Fall die zeitliche Komplexität ?quelle
Der Wert wird mit dem Standardkonstruktor initialisiert, wie in den anderen Antworten angegeben. Es ist jedoch nützlich hinzuzufügen, dass bei einfachen Typen (integrale Typen wie int, float, pointer oder POD (Plan Old Data) -Typen) die Werte auf Null initialisiert (oder durch Wertinitialisierung auf Null gesetzt) werden (was effektiv ist das gleiche), abhängig davon, welche Version von C ++ verwendet wird).
Unter dem Strich werden Karten mit einfachen Typen die neuen Elemente automatisch auf Null initialisieren. In einigen Fällen müssen Sie sich also nicht darum kümmern, den Standardanfangswert explizit anzugeben.
Siehe Machen die Klammern nach dem Typnamen einen Unterschied zu new? für weitere Details zu diesem Thema.
quelle
Eine Problemumgehung ist die Verwendung von
map::at()
anstelle von[]
. Wenn kein Schlüssel vorhanden ist, wirdat
eine Ausnahme ausgelöst. Noch schöner ist, dass dies auch für Vektoren funktioniert und sich daher für die generische Programmierung eignet, bei der Sie die Karte gegen einen Vektor austauschen können.Die Verwendung eines benutzerdefinierten Werts für nicht registrierte Schlüssel kann gefährlich sein, da dieser benutzerdefinierte Wert (wie -1) möglicherweise weiter unten im Code verarbeitet wird. Mit Ausnahmen ist es einfacher, Fehler zu erkennen.
quelle
Möglicherweise können Sie einen benutzerdefinierten Zuweiser angeben, der einen gewünschten Standardwert zuweist.
quelle
operator[]
Gibt ein durch Aufrufen erstelltes Objekt zurückT()
, unabhängig davon, was der Allokator tut.construct
? Das könnte man ändern, denke ich. Ich vermute jedoch eineconstruct
Funktion, die nichts anderes tut alsnew(p) T(t);
nicht gut geformt ist. EDIT: Im Nachhinein war das dumm, sonst wären alle Werte gleich: P Wo ist mein Kaffee ...operator[]
zurückgegeben wird(*((insert(make_pair(x, T()))).first)).second
. Wenn mir also nichts fehlt, ist diese Antwort falsch.insert
mit aT()
, aber innerhalb von insert wird der Allokator verwendet, um Speicher für einen neuen SpeicherT
aufzurufenconstruct
und diesen Speicher mit dem angegebenen Parameter aufzurufenT()
. Es ist also tatsächlich möglich, das Verhalten zu ändernoperator[]
, damit es etwas anderes zurückgibt, aber der Allokator kann nicht unterscheiden, warum es aufgerufen wird. Selbst wenn wirconstruct
den Parameter ignorieren und unseren speziellen Wert verwenden würden, würde dies bedeuten, dass jedes konstruierte Element diesen Wert hat, was schlecht ist.Verwenden Sie
std::map::insert()
.Wenn Sie
operator[]
feststellen, dass ich zu spät zu dieser Party komme, aber wenn Sie sich für das Verhalten mit benutzerdefinierten Standardeinstellungen interessieren (dh das Element mit dem angegebenen Schlüssel suchen, wenn es nicht vorhanden ist, fügen Sie ein Element mit einem in die Karte ein Standardwert gewählt und einen Verweis entweder auf den neu eingefügten Wert oder auf den vorhandenen Wert zurückgegeben). Vor C ++ 17 steht Ihnen bereits eine Funktion zur Verfügung :std::map::insert()
.insert
wird nicht eingefügt, wenn der Schlüssel bereits vorhanden ist, sondern einen Iterator auf den vorhandenen Wert zurücksetzen.Angenommen, Sie wollten eine Zuordnung von String zu Int und fügen einen Standardwert von 42 ein, wenn der Schlüssel noch nicht vorhanden war:
welches 42, 43 und 44 ausgeben sollte.
Wenn die Kosten für die Erstellung des Kartenwerts hoch sind (wenn entweder das Kopieren / Verschieben des Schlüssels oder der Werttyp teuer ist), führt dies zu einem erheblichen Leistungsverlust, der meiner Meinung nach mit C ++ 17 umgangen werden würde
try_emplace
.quelle
Diese Vorlagenfunktion erweitert die Antwort https://stackoverflow.com/a/2333816/272642 und verwendet
std::map
'skey_type
undmapped_type
typedefs, um den Typ vonkey
und abzuleitendef
. Dies funktioniert nicht mit Containern ohne diese Typedefs.Dies ermöglicht Ihnen die Verwendung
ohne die Argumente wie zu werfen
std::string("a"), (int*) NULL
.quelle