c++ - valgrind 发现很难发现的泄漏

标签 c++ memory-leaks valgrind destructor

这是程序的一部分。当我用 g++ 编译它时,它编译并工作正常,但 valgrind 说肯定有丢失:泄漏摘要中的 8 个 block 中有 256 个字节。我缩小了发生内存泄漏的部分。我尝试了不同的方法来修复它,但 valgrind 不断发现错误摘要:来自 1 个上下文的 1 个错误(抑制:来自 0 的 0)。主要泄漏发生在调用 buildTree 函数时。我该如何解决?

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

谢谢

    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)

最佳答案

您的 insertHelper 代码已损坏,因为当它递归调用 insertHelper 时,它会忽略返回值并返回 true,即使对象不是' t 插入,导致泄漏。

取而代之的是:

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

你需要这个:

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

你为什么要使用裸指针?

关于c++ - valgrind 发现很难发现的泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40150021/

相关文章:

c++ - valgrind 中的段错误,但在实际运行中没有

wpf - WPF 中的 CollectionViewSource.GetDefaultView() 内存泄漏?

php - 我的脚本中是否存在内存泄漏,或者是另一个罪魁祸首?

c - 使用 fscanf 时调试 seg 错误时出现问题

c++ - 为什么编译器在某些情况下看不到模板类中的错误?

c - 链表按顺序插入和内存泄漏

linux - Valgrind 时间限制

c++ - 2种类型的多维数组cpp

c++ - 计算不同数字数量的省时方法

c++ - 程序在调用 Wincrypt 函数时挂起