2017-11-20 6 views
0

Ich definierte eine einfache Struktur EdgeList, die einfach eine unordered_map Assoziation eines String-Schlüssels mit einer set von Strings ist.C++: segfault beim Zugriff auf Daten in unordered_map zu setzen

class EdgeList{ 
private: 
    std::unordered_map<std::string,std::set<std::string>> map; 

public: 
    EdgeList(){}; 

    void insert(std::string key,std::string item); 

    std::set<std::string> operator[](std::string key); 
}; 

void EdgeList::insert(std::string key,std::string item) 
{ 
    if(map.count(key)==0) //key not already in map 
    { 
    std::set<string> newset; 
    map.emplace(key,newset); 
    } 
    map[key].insert(item); 
} 

std::set<string> EdgeList::operator[](string key){ 
    return map[key]; 
} 

EdgeList::insert nur überprüft, wenn der Schlüssel existiert bereits in den unordered_map (einen neuen Satz, wenn nicht zu schaffen) und fügt das Element in den zugehörigen Satz. EdgeList::operator[] gibt den Satz zurück, der dem Eingabeschlüssel zugeordnet ist.

Das ist alles einfach genug, aber etwas schief geht, wenn ich versuche, auf die Daten in einem EdgeList zuzugreifen. Ich bekomme immer mysteriöse segfaults, wenn ich etwas versuche, wie

EdgeList el; 
//populate el 
string KeyInEdgeList; 

for(auto it=el[KeyInEdgeList].begin();it!=el[KeyInEdgeList].end();++it) 
{ 
    std::cout << *it << std::endl; 
} 

Was könnte los sein? Gibt es einen Fehler in der Klassendefinition? Kann ich aus irgendeinem Grund keine Iteratoren verwenden? Ich bin am Ende meines Wissens, das sollte nicht kompliziert sein.

+0

'std :: map' des' operator [] '[a erzeugt Schlüssel, wenn es nicht existiert] (http://en.cppreference.com/w/cpp/container/map/operator_at), so dass Ihre 'if' Anweisung in' insert (string, string) 'redundant ist. Aus dem gleichen Grund erstellen Sie in der 'for'-Schleife eine leere Menge mit' operator [] 'und versuchen dann, den Iterator auf der leeren Menge innerhalb der Schleife zu dereferenzieren. – cantordust

Antwort

0

Ihr operator[] liefert einen Wert:

std::set<std::string> operator[](std::string key); 
^^^^^^^^^^^^^^^^^^^^^ 

Das heißt, eine neue std::set von Ihrem zugrunde liegenden Karte Sie diese Funktion aufrufen, jedes Mal kopiert, die dann am Ende des Ausdrucks zerstört wird erhalten. Mit anderen Worten:

for(auto it=el[KeyInEdgeList].begin();it!=el[KeyInEdgeList].end();++it) 
//   |--- 1st set ---|    |--- 2nd set ---| 

Das sind zwei verschiedene set s, die beide von der Zeit zerstört werden Sie tatsächlich dereferenzieren Ihre Iterator. Innerhalb des Körpers der for Schleife haben Sie eine baumelnde Referenz.

Was möchten Sie ist zu tun zu haben, Ihr operator[] einen Verweis zurückgeben und dann unabhängig, verwenden Sie eine bereichsbasierte für:

for (std::string const& elem : el[KeyInEdgeList]) { ... }