How to write a correct Hash Table destructor in c+

2020-03-27 05:41发布

问题:

I am writing a c++ Hashtable

Here is my destructor:

HashMap::~HashMap()
{
    for (int i=0; i<cap; i++)
    {
        Node* ptr = Hashtable[i];
        while (ptr!=NULL)
        {
            Node* delptr;
            delptr=ptr;
            ptr=ptr->next;
            delete delptr;
        }
    }
    delete [] Hashtable;
}

My add function:

void HashMap::add(const std::string& key, const std::string& value)
{
    int index = hashfunction(key)%cap;;

    Node* ptr=Hashtable[index];
    Node* newnode=new Node;

    if (contains(key)==false)
    {
        if (ptr == nullptr)
        {

            newnode->key=key;
            newnode->value=value;
            newnode->next=NULL;
            Hashtable[index]=newnode;
        }
        else
        {
            newnode->key=key;
            newnode->value=value;
            newnode->next=NULL;

            while(ptr->next != NULL)
            {
                ptr = ptr->next;
            }
            ptr->next=newnode;
         }}}

But I keeps getting memory leak error

==13676== 
==13676== HEAP SUMMARY:
==13676==     in use at exit: 12 bytes in 1 blocks
==13676==   total heap usage: 42 allocs, 41 frees, 669 bytes allocated
==13676== 
==13676== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13676==    at 0x402BE94: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==13676==    by 0x804BF8D: HashMap::add(std::string const&, std::string const&) (HashMap.cpp:112)
==13676==    by 0x804AFD2: main (main.cpp:18)
==13676== 
==13676== LEAK SUMMARY:
==13676==    definitely lost: 12 bytes in 1 blocks
==13676==    indirectly lost: 0 bytes in 0 blocks
==13676==      possibly lost: 0 bytes in 0 blocks
==13676==    still reachable: 0 bytes in 0 blocks
==13676==         suppressed: 0 bytes in 0 blocks
==13676== 
==13676== For counts of detected and suppressed errors, rerun with: -v
==13676== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

The line its indicates is Node* newnode=new Node; because I use "new" here, this newnode needed to be deallocated, but the destructor only deallocate content in Hashtable. If I don't use "newnode", I will have null-pointer access error because nullptr does not have access to Node (Node is a struct has key and value), I can only let the pointer points to a "newnode."However, adding extra "delete newnode" makes me getting more than 20 errors. I really need you help!

If I write this, I still get an error

if (contains(key)==false)
{
    if (ptr == nullptr)
    {
        Node* newnode=new Node;
        newnode->key=key;
        newnode->value=value;
        newnode->next=NULL;
        Hashtable[index]=newnode;
    }
    else
    {
        Node* newnode=new Node;
        newnode->key=key;
        newnode->value=value;
        newnode->next=NULL;

        while(ptr->next != NULL)
        {
            ptr = ptr->next;
        }
        ptr->next=newnode;
     }}

回答1:

This line

Node* newnode=new Node; 

creates a local newnode pointer which will go out of scope after the add function exits. This will leak memory allocated by new.



回答2:

The problem is that you are doing this:

Node* newnode=new Node;
if (contains(key)==false)
    // ... store it
/*
else
    leak it
*/

What you need to do is do the conditional BEFORE the new.

if(contains(key) == true) {
     // use the existing entry.
     ...
     return;
}
else {
    Node* newnode=new Node;
    // ... rest of your code for inserting a new entry here.
}

---- Edit ----

What ValGrind is telling you is that your code allocated a pointer at HashMap.cpp line 112, but it never stored the address -- this is what happens in your code when someone calls the add function with a key for which "contains(key)" does not return false. You don't store the pointer, and so the Node you allocated is left allocated but your code is not tracking it -> it's a leak.



回答3:

Simply declare the newnode and then after the if statement allocate the new Node. The way your code is right now the newnode can be allocated , the if statement goes wrong and the newnode stays in memory never used.