2016-10-20 1 views
1

Dies ist Teil eines Programms. Wenn ich es mit g ++ kompiliere, kompiliert es und funktioniert gut, aber Valgrind sagt, dass es definitiv verloren ist: 256 Bytes in 8 Blöcken in der Leckübersicht. Ich habe den Teil eingeengt, an dem das Speicherleck passiert. Ich habe verschiedene Dinge ausprobiert, um es zu beheben, aber Valgrind findet immer Fehler: 1 Fehler aus 1 Kontexten (unterdrückt: 0 von 0). Das Hauptleck tritt auf, wenn die buildTree-Funktion aufgerufen wird. wie kann ich es reparieren?Valgrind Finden von Lecks, die schwer zu finden sind

#include <fstream> 
#include <iostream> 
using namespace std; 

const int ARRAYSIZE = 100; 

class NodeData { 
     friend ostream & operator<<(ostream &, const NodeData &); 
public: 
     NodeData();   // default constructor, data is set to an empty string 
     ~NodeData(); 
     NodeData(const string &);  // data is set equal to parameter 
     NodeData(const NodeData &); 
     bool setData(istream&); 

     bool operator==(const NodeData &) const; 
     bool operator!=(const NodeData &) const; 
     bool operator<(const NodeData &) const; 
     bool operator>(const NodeData &) const; 
private: 
     string data; 
}; 

NodeData::NodeData() { data = ""; }       // default 

NodeData::~NodeData() { }   // needed so strings are deleted properly 

NodeData::NodeData(const NodeData& nd) { data = nd.data; } // copy 

NodeData::NodeData(const string& s) { data = s; } 

bool NodeData::operator==(const NodeData& rhs) const { 
     return data == rhs.data; 
} 

bool NodeData::operator!=(const NodeData& rhs) const { 
     return data != rhs.data; 
} 

//------------------------ operator<,>,<=,>= --------------------------------- 
bool NodeData::operator<(const NodeData& rhs) const { 
     return data < rhs.data; 
} 

bool NodeData::operator>(const NodeData& rhs) const { 
     return data > rhs.data; 
} 

bool NodeData::setData(istream& infile) { 
     getline(infile, data); 
     return !infile.eof();  // eof function is true when eof char is read 
} 

//-------------------------- operator<< -------------------------------------- 
ostream& operator<<(ostream& output, const NodeData& nd) { 
     output << nd.data; 
     return output; 
} 

class BinTree 
{ 
    public: 
     BinTree();      // default constructor 
     BinTree(const BinTree&);    // copy constructor 
     ~BinTree(); 
    void makeEmpty(); 
    bool insert(NodeData*); 
    private: 
     struct Node 
     { 
       NodeData* data;   // pointer to data object 
       Node* left;    // left subtree pointer 
       Node* right;   // right subtree pointer 
     }; 
     Node* root;      // root of the tree 
     void makeEmptyHelper(Node*&); 
     bool insertHelper(Node*&, NodeData*); 
}; 


BinTree::BinTree() 
{  
     root = NULL; 
} 

BinTree::BinTree(const BinTree& bt) 
{  
     this->root = NULL; 
     *this = bt; 
} 

BinTree::~BinTree() 
{  
     makeEmpty(); 
} 

void BinTree::makeEmpty() 
{  
     makeEmptyHelper(root); 
} 

void BinTree::makeEmptyHelper(Node*& current) 
{  
     if (current != NULL) 
     {  
       if (current->data != NULL) 
       {  
         delete current->data; 
         current->data = NULL; 
       } 
       makeEmptyHelper(current->left); 
       makeEmptyHelper(current->right); 
       delete current; 
       current = NULL; 
     } 
     delete current; 
} 

bool BinTree::insert(NodeData* insertion) 
{ 
     return insertHelper(root, insertion); 
} 

bool BinTree::insertHelper(Node*& current, NodeData* insertion) 
{ 
     if (current == NULL) 
     { 
       current = new Node; 
       current->data = insertion; 
       current->left = NULL; 
       current->right = NULL; 
       //delete insertion; 
     } 
     else if (*insertion < *current->data) 
     { 
       insertHelper(current->left, insertion); 
     } 
     else if (*insertion > *current->data) 
     { 
       insertHelper(current->right, insertion); 
     } 
     else 
     { 
       return false; 
     } 
     return true; 
} 

void buildTree(BinTree&, ifstream&); 

int main() 
{  
     ifstream infile("data2.txt"); 
     if (!infile) 
     {  
       cout << "File could not be opened." << endl; 
       return 1; 
     } 

     BinTree T; 
     cout << "initial data:" << endl << " "; 
     buildTree(T, infile); 
     cout << endl; 

     NodeData* p; // pointer of retrieved object 
     bool found;  // whether or not object was found in tree 

     return 0; 
} 

void buildTree(BinTree& T, ifstream& infile) 
{ 
     string s; 

     for (;;) 
     { 
       infile >> s; 
       cout << s << ' '; 
       if (s == "$$") break; 
       if (infile.eof()) break; 

       NodeData* ptr = new NodeData(s); 

       bool success = T.insert(ptr); 
       if (!success) 
         delete ptr; 
     } 
} 

dank

valgrind --leak-check=full --show-leak-kinds=all ./a.out 
==2201== Memcheck, a memory error detector 
==2201== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==2201== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 
==2201== Command: ./a.out 
==2201== 
initial data: 
iii not tttt eee r not and jj r eee pp r sssss eee not tttt ooo ff m m y z $$ 
==2201== 
==2201== HEAP SUMMARY: 
==2201==  in use at exit: 72,960 bytes in 9 blocks 
==2201== total heap usage: 40 allocs, 31 frees, 83,512 bytes allocated 
==2201== 
==2201== 256 bytes in 8 blocks are definitely lost in loss record 1 of 2 
==2201== at 0x4C2A0FC: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==2201== by 0x401820: buildTree(BinTree&, std::basic_ifstream<char, std::char_traits<char> >&) (new.cpp:187) 
==2201== by 0x401718: main (new.cpp:168) 
==2201== 
==2201== 72,704 bytes in 1 blocks are still reachable in loss record 2 of 2 
==2201== at 0x4C29BBE: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==2201== by 0x4EC0A1F: pool (eh_alloc.cc:123) 
==2201== by 0x4EC0A1F: __static_initialization_and_destruction_0 (eh_alloc.cc:250) 
==2201== by 0x4EC0A1F: _GLOBAL__sub_I_eh_alloc.cc (eh_alloc.cc:326) 
==2201== by 0x400F4F9: call_init.part.0 (in /usr/lib/ld-2.24.so) 
==2201== by 0x400F60A: _dl_init (in /usr/lib/ld-2.24.so) 
==2201== by 0x4000DA9: ??? (in /usr/lib/ld-2.24.so) 
==2201== 
==2201== LEAK SUMMARY: 
==2201== definitely lost: 256 bytes in 8 blocks 
==2201== indirectly lost: 0 bytes in 0 blocks 
==2201==  possibly lost: 0 bytes in 0 blocks 
==2201== still reachable: 72,704 bytes in 1 blocks 
==2201==   suppressed: 0 bytes in 0 blocks 
==2201== 
==2201== For counts of detected and suppressed errors, rerun with: -v 
==2201== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 
+0

Können Sie bitte die Valgrind-Ausgabe einbeziehen? Und Sie führen einen Debug-Build aus? I.e. hast du beim Bauen die '-g'-Flagge? Und nicht die ausführbare Datei von Debug-Informationen zu strippen? –

+0

Und vielleicht ein Haupt, um die problematische Funktion zu testen? – deviantfan

+1

Vielleicht sollten Sie nicht 'neue' Operator ohne ein' std :: unique_ptr' verwenden und dann haben Sie dieses Problem überhaupt nicht ... Haben Sie einen besonderen Grund, warum Sie Speicher selbst verwalten müssen und kein Smart Zeiger tun es für Sie? Hier ist ein Link dazu: http://en.cppreference.com/w/cpp/memory/unique_ptr –

Antwort

2

Ihr insertHelper Code gebrochen ist, weil, wenn es insertHelper rekursiv aufruft, wird der Wert Rückkehr ignoriert und gibt true auch wenn das Objekt nicht eingefügt wurde, zu einem Leck führen.

Statt dessen:

else if (*insertion < *current->data) 
    { 
      insertHelper(current->left, insertion); 
    } 
    else if (*insertion > *current->data) 
    { 
      insertHelper(current->right, insertion); 
    } 

Sie müssen dies:

else if (*insertion < *current->data) 
    { 
      return insertHelper(current->left, insertion); 
    } 
    else if (*insertion > *current->data) 
    { 
      return insertHelper(current->right, insertion); 
    } 

Warum sind Sie mit nackten Zeiger überhaupt?

+0

, dass das Problem behoben Vielen Dank – stset

+0

Was meinst du nackte Zeiger? – stset

+0

Ich meine einen Zeiger, der nicht in irgendeiner Art von Logik verpackt ist, um zu ermöglichen, dass seine Lebensdauer intelligent verwaltet wird, und Sie gezwungen werden, ihn manuell zu verwalten. (Welche, wie Sie sehen können, ist leicht falsch zu verstehen.) –

Verwandte Themen