2016-06-05 22 views
1

ich folgendes, wenn ich mein Programm durch valgrind laufenValgrind: Ungültige Lese der Größe 8 Fehler

==29852== Invalid read of size 8 
==29852== at 0x4EDEA50: std::_Rb_tree_increment(std::_Rb_tree_node_base const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21) 
==29852== by 0x414EEA: std::_Rb_tree_const_iterator<std::pair... >::operator++() (stl_tree.h:284) 
==29852== by 0x4268CF: Tree::removeConstantsPair(std::set...) (Tree.h:65) 
==29852== by 0x4239C4: yy_reduce(yyParser*, int) (parser.y:251) 
==29852== by 0x425F6D: Parse(void*, int, Token*, Tree*) (parser.c:1418) 
==29852== by 0x404837: main (main.cpp:95) 

Linie 65 in Tree.h ist

inline void removeConstantsPair(set<pair<string, string>>& vec){ 
    set<string>::iterator itr; 
    for(auto &v : vec){ //This is line 65 
     itr = domainList.find(v.first); 
     if(itr != domainList.end()) 
      vec.erase(v); 
    } 
} 

jedoch die Zusammenfassung Leak sagt, dass es ist keine Erinnerung, die verloren ist. Von dem, was ich verstehe, ungültiges Lesen passiert, wenn ich aus einem Speicher, der in meinem Fall freigegeben wurde lesen &vec muss zuvor freigegeben worden sein. Mein Programm läuft und stürzt nicht ab.

Kann jemand erklären, warum es einen Gedächtnislesefehler gibt.

+1

'std :: set :: erase()' macht den Iterator ungültig, der gelöscht wird. Was passiert, wenn ein Inkrement auf den gelöschten Iterator angewendet wird? So sieht dieser Fehlerbericht aus (wobei der Operator ++() 'verwendet wird). – PaulMcKenzie

Antwort

4

Das Problem wird wahrscheinlich durch die Linie verursacht: ist keine gute Idee

 vec.erase(v); 

einen Bereich für Schleife und ein Element aus dem Container zu löschen. Ändern Sie Ihre Schleife:

for (auto iter = vec.begin(); iter != vec.end(); /* Empty on purpose*/) 
{ 
    if(domainList.find(iter->first) != domainList.end()) 
    { 
     iter = vec.erase(iter); 
    } 
    else 
    { 
     ++iter; 
    } 
} 
+0

Das hat funktioniert! Gibt es ein g ++ - Compiler-Flag, das dieses Verhalten auffängt? –

+0

@SamidhT, keine, die ich kenne. –

1

Ein "ungültiger Speicher gelesen" kann auch aus vielen anderen Gründen auftreten, außer denen, die in der Frage angegeben sind.

Ein Beispiel:

Eine Anforderung Speicher zuzuweisen, über new typischerweise ein wenig mehr Speicher als zuordnet, was für die Instanz einer neuen Klasse benötigt wird. Zum Beispiel könnte eine bestimmte C++ - Implementierung Speicher in mehreren von 16 Bytes zuweisen. Ein new für eine Instanz einer Klasse, deren sizeof 12 zurückgeben würde, wird am Ende tatsächlich 16 Bytes zuweisen, und ein Versuch, nach dem Ende des tatsächlichen instanziierten Objekts zu lesen, wird korrekt von valgrind als ungültiger Speicher gelesen markiert werden .

1

Das folgende kleine Programm zeigt den Fehler, wenn sie unter dem Visual Studio Compiler laufen:

#include <string> 
#include <set> 
#include <map> 

std::set<std::string> domainList = {"abc", "123", "456"}; 

using namespace std; 

void removeConstantsPair(set<pair<string, string>>& vec) 
{ 
    set<string>::iterator itr; 
    for(auto &v : vec) 
    { 
     itr = domainList.find(v.first); 
     if(itr != domainList.end()) 
      vec.erase(v); // <--erasing this iterator makes it invalid 
    } 
} 

int main() 
{ 
    std::set<std::pair<string, string>> vec = {make_pair("abc", "xyz"), 
               make_pair("456", "xyz"), 
               make_pair("000", "xyz")}; 
    removeConstantsPair(vec); 
} 

Das Visual Studio Debug-Runtime behauptet mit einem „Expression Karte/set Iterator nicht inkrementierbarer "Wenn das Inkrement auf dem gelöschten Iterator in der for-Schleife versucht wird.

enter image description here

So ist die Lösung, um sicherzustellen, dass der Iterator, nicht derjenige, der gelöscht werden erhöht wird war wurde.

void removeConstantsPair(set<pair<string, string>>& vec) 
{ 
    set<string>::iterator itr; 
    auto iterSet = vec.begin(); 
    while (iterSet != vec.end()) 
    { 
     itr = domainList.find((*iterSet).first); 
     if (itr != domainList.end()) 
     { 
      auto erasedIter = iterSet; 
      ++iterSet; 
      vec.erase(erasedIter); 
     } 
     else 
      ++iterSet; 
    } 
} 
Verwandte Themen