当我看到levelDB的缓存,地址的实现。我不明白为什么它在for循环中使用while循环(在函数Resize中),我认为它可以用if语句代替。我希望有人能帮助我。
void Resize() {
uint32_t new_length = 4;
while (new_length < elems_) {
new_length *= 2;
}
LRUHandle** new_list = new LRUHandle*[new_length];
memset(new_list, 0, sizeof(new_list[0]) * new_length);
uint32_t count = 0;
for (uint32_t i = 0; i < length_; i++) {
LRUHandle* h = list_[i];
while (h != NULL) {
LRUHandle* next = h->next_hash;
uint32_t hash = h->hash;
LRUHandle** ptr = &new_list[hash & (new_length - 1)];
h->next_hash = *ptr;
*ptr = h;
h = next;
count++;
}
}
assert(elems_ == count);
delete[] list_;
list_ = new_list;
length_ = new_length;
}
};
list_
显然是一个链表数组。while (h != NULL)
,结合h = next
(其中next
为h->next_hash
),意味着while循环将对每个链表的所有元素进行操作,仅在到达最后一个元素时停止(当h
变为NULL
时,要么是因为列表为空,要么是因为元素的next_hash
为NULL
)。
如果你用if (h != NULL)
替换它,它将只对链表的第一个元素起作用
看起来list_是一个动态的单链表数组。
我假设list_看起来像下面的
list_[0]-> node_1 -> node_2 -> null
list_[1]-> node_3 -> null
list_[2]-> null
....
list_[n]-> node_m-1 -> node_m -> null
要正确地将所有元素复制到new_list中,需要使用while循环。否则,任何不能从list_直接寻址的元素都不会被复制/散列到new_list中。在上面的图中,这意味着node_2和node_m+1不会被添加到new_list中。
new_list将保持相同的形状,但应该有更少的冲突。
使用if语句,new_list看起来像这样:new_list[0]-> node_1 -> null
new_list[1]-> null
new_list[2]-> node_2 -> null
...
new_list[p-1]-> node_k -> null
new_list[p] -> null
即new_list中的每一项都指向一个包含1个或0个元素的列表。注意,该图中的node_1不一定与上图中的节点1相同。
使用If语句而不是while循环也会导致内存泄漏,因为您不能再访问所有元素。
变量list_[i]
有一个子列表,while
在for
循环中循环遍历子列表
if语句不起作用,如果您有两个元素list_[i]
和list_[j]
都散列到同一个索引new_list[m]
。在这种情况下,您必须使用while语句来合并两个桶。同时,这个实现中每个bucket的长度平均小于1,所以这里的while语句实际上和if语句一样快。