哈希 Table - 条件跳转或移动取决于未初始化的值

Hash Table - Conditional jump or move depends on uninitialised value(s)

我正在为我的 类 之一使用双向链表编写哈希表,但是当我 运行 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)

所以我认为问题出在我的重新散列函数中,但我不知道它在哪里。你们能帮帮我吗?这是我的重新哈希函数:

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;

}

这是我的哈希集构造函数:

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

这是我的 LinkedList 的构造函数:

LinkedList()
{
    size = 0;
}

谢谢!

我要在这里做个幸运的猜测:你的 LinkedList 包含一个 head 指针,你的 itemExists 函数在检查 size 之前加载该指针字段大于零。

类似

Node* node = head;
for (size_t i = 0; i < size; i++)
{
    if (node->hash == ...)
    ...
    node = node->next;
}

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

天哪,这很难发现。如果这不是@PaulGroke 已经建议的,那么这里还有一个潜在的问题:

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

根据您的 rehash 成员函数,我猜测您的散列集 class 有一个名为 tableSize 的成员。上面的构造函数有一个与 shadows 这个成员同名的局部变量。因此,成员字段永远不会被初始化,并且您有未定义的行为。删除标记的 int 应该可以解决这个问题。

一般来说,你应该使用初始化列表来编写你的构造函数:

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

虽然是否应该像我上面那样对分配进行此操作值得商榷,但通常你根本不应该在代码中使用原始 newnew [],更好的是 std::shared_pointer/std::unique_pointerstd::vector.