哈希表 - 条件跳转或移动取决于未初始化的值(s)

时间:2015-08-05 22:46:38

标签: c++ hashtable valgrind

我正在为我的一个类使用Doubly Linked列表编写HashTable,但是当我运行valgrind时遇到错误。它说:条件跳跃或移动取决于未初始化的值。当我运行--track-origins = yes时,它说:

==11453== Conditional jump or move depends on uninitialised value(s)
==11453==    at 0x402904: LinkedList<std::string>::itemExists(std::string const&) (LinkedList.h:89)
==11453==    by 0x401FE6: HashSet<std::string>::find(std::string const&) (HashSet.h:85)
==11453==    by 0x401E42: HashSet<std::string>::add(std::string const&) (HashSet.h:39)
==11453==    by 0x4019D7: insert(std::string, std::basic_ifstream<char, std::char_traits<char> >&, std::basic_ofstream<char, std::char_traits<char> >&, std::string, HashSet<std::string>&) (main.cpp:64)
==11453==    by 0x4015B1: main (main.cpp:34)
==11453==  Uninitialised value was created by a heap allocation
==11453==    at 0x4C2B800: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11453==    by 0x4024D8: HashSet<std::string>::rehash() (HashSet.h:131)
==11453==    by 0x401E69: HashSet<std::string>::add(std::string const&) (HashSet.h:45)
==11453==    by 0x4019D7: insert(std::string, std::basic_ifstream<char, std::char_traits<char> >&, std::basic_ofstream<char, std::char_traits<char> >&, std::string, HashSet<std::string>&) (main.cpp:64)
==11453==    by 0x4015B1: main (main.cpp:34)

所以我认为问题在于我的rehash功能,但我无法弄清楚它在哪里。你能帮助我吗?这是我的rehash功能:

void rehash()
{
    int old_size = tableSize;
    if (tableSize == itemsStored) {
        tableSize = tableSize * 2 + 1;
    }

    else if (itemsStored <= tableSize/2) {
        tableSize = tableSize / 2;
    }
        LinkedList<string>* newTable = new LinkedList<string>[tableSize];    -------> line 131
        for (int i = 0; i < old_size; ++i)
        {
            int table_size = 0;
            table_size = table[i].getSize();
            if(table_size != 0) {
                for (int j = 0; j < table_size; ++j) {
                        unsigned index = hashFunction(table[i].getItem(j)) % tableSize;
                        newTable[index].insert(newTable[index].getSize(), table->getItem(i));

                }
            }
        }
        LinkedList<string>* temp = table;
        table = newTable;
        delete [] temp;

}

这是Hash Set的构造函数:

HashSet()
{
    int tableSize = 0;
    table = new LinkedList<string>[tableSize];
}

这是LinkedList的构造函数:

LinkedList()
{
    size = 0;
}

谢谢!

2 个答案:

答案 0 :(得分:1)

我将在这里做一个幸运的猜测:你的LinkedList包含一个head指针,你的itemExists函数会在检查size字段是否为Node* node = head; for (size_t i = 0; i < size; i++) { if (node->hash == ...) ... node = node->next; } 之前加载该指针大于零。

这样的东西
size == 0

看起来无辜,因为如果helloWorld指针没有被解除引用,但读取未初始化的指针本身就是UB。

答案 1 :(得分:0)

哦,我的,很难发现。如果不是@PaulGroke已经提出的建议,那么这里也存在一个潜在的问题:

HashSet()
{
    /* */int/* */ tableSize = 0; // HERE!
    table = new LinkedList<string>[tableSize];
}

从你的rehash成员函数我猜你的哈希集类有一个名为tableSize的成员。上面的构造函数有一个局部变量,其名称与 shadows 这个成员相同。因此,成员字段永远不会初始化,并且您具有未定义的行为。删除标记的int应解决此问题。

通常,您应该使用初始化列表来编写构造函数:

HashSet()
 : tableSize(0), 
   table(new LinkedList<string>[tableSize]); {
}

虽然我是否应该按照上面的说法对分配进行分析,这是值得商榷的,但是你通常不应该在代码中使用原始newnew [],更好std::shared_pointer / std::unique_pointerstd::vector