可以在C ++中实现XOR链表而不会导致未定义的行为吗?

时间:2013-01-09 18:28:39

标签: c++ data-structures linked-list language-lawyer xor

XOR linked list 是普通双向链表的修改版,其中每个节点只存储一个“指针”而不是两个。该“指针”由下一个和前一个指针的XOR组成。要遍历列表,需要两个指针 - 一个指向当前节点,一个指向下一个或上一个节点。为了遍历,前一个节点的地址与存储在当前节点中的“指针”进行异或,显示真正的“下一个”指针。

C ++标准导致指针和整数上的一系列操作导致未定义的行为 - 例如,您无法保证在数字中设置特定位不会导致硬件触发中断,因此在某些情况下bit twiddling的结果可能是不确定的。

我的问题如下:是否存在XOR链表的C ++实现,不会导致未定义的行为?

1 个答案:

答案 0 :(得分:16)

  

我的问题如下:是否存在XOR链表的C ++实现,不会导致未定义的行为?

如果“有实施”,你的意思是“已经写好了”那么我不知道。如果你的意思是“是否有可能写一个”,那么是的,但可能有一些关于可移植性的警告。

如果在开始之前将两个指针都转换为uintptr_t,并且将该类型存储在节点而不是指针中,则可以根据自己的内容进行调整。对无符号类型的按位运算决不会导致未定义的行为。

但是,uintptr_t是一种可选类型,因此它不是完全可移植的。不要求C ++实现实际上具有能够表示地址的整数类型。如果实现没有uintptr_t,则允许使用诊断编译代码,在这种情况下,其行为超出了标准的范围。不确定您是否认为侵犯了“没有UB”。我认真地说,一个允许使用未定义类型的代码的编译器? ; - )

为了避免uintptr_t认为你可以在sizeof(node*)无符号字符数组上做一点点麻烦。指针是POD类型,因此只要对象表示在用作指针之前恢复到其原始状态,就可以复制,修剪和删除。

另请注意,如果您的C ++实现具有垃圾收集器,则转换为整数/ xor / xor-back-again / convert-to-pointer不必停止收集对象(因为它会导致“不安全的派生指针”)。因此,为了便于移植,您必须确保生成的指针有效。有两种方法可以做到这一点:

  1. 打电话给declare_reachable
  2. 使用带有轻松指针安全性的实现(实现已定义是否是这种情况,您可以使用get_pointer_safety()对其进行测试,同时考虑到允许放宽的实现错误地声称它是严格的。)
  3. 你可能会认为还有第三种方式(尽管有一种方法会破坏XOR链接列表的目的,除非您碰巧拥有它):

    • 保留所有指针值的单独容器

    这不能保证正常工作。即使它恰好等于安全派生的指针(3.7.4.3/4),不安全派生的指针也是无效的。我也很惊讶。