指针如何完全有序? C++中的指针一般只能比较相等。相比之下,只有指向同一完整对象的子对象(例如数组元素)的两个指针才允许小于比较

指针如何完全有序? C++中的指针一般只能比较相等。相比之下,只有指向同一完整对象的子对象(例如数组元素)的两个指针才允许小于比较,c++,pointers,predicate,standard-library,C++,Pointers,Predicate,Standard Library,因此,给定T*p,*q,通常对p

因此,给定
T*p,*q
,通常对
p
进行评估是非法的

标准库包含函子类模板
std::less
等,这些模板包装了内置运算符

在指针不形成全局总顺序的目标上,是否可以实现标准库

对。给定任何一个有限集,你总是可以在它上面定义一个任意的总阶

考虑一个简单的例子,其中只有五个可能的不同指针值。让我们称之为O(对于nullptr),γ,ζ,χ,ψ1


假设四个非空指针中的两个不同指针对不能与
相比,在大多数具有平坦地址空间的平台上,它们可以简单地在指针之间进行数字比较。在无法实现这一点的平台上,实现者必须想出一些其他方法来建立在
std::less
中使用的总顺序,但他们可能会对
使用更有效的方法。问题是分段体系结构,其中内存地址有两部分:段和偏移量。将这些片段转换成某种线性形式“非常容易”,但这需要额外的代码,而决策是不为
操作符施加开销指针可以完全有序吗?不是便携式的,标准的C++。那是
为什么标准要求实施来解决问题,而不是
你。对于指针的任何给定表示形式,都应该是可能的
定义任意的总排序,但如何定义将取决于
指针的表示形式

对于具有平坦地址空间和字节寻址的计算机,只需 将指针视为大小相似的整数或无符号指针 整数通常就足够了;这是大多数编译器将处理的方式 对象内部的比较也是如此,所以在这样的机器上,没有 图书馆需要专门化
std::less
等“未指定” 行为只是碰巧做了正确的事情

对于字寻址机器(至少有一台仍在使用中) 生产),可能需要将指针转换为
void*
在编译器本机比较开始工作之前

对于具有分段体系结构的机器,可能需要进行更多的工作。 在这样的机器上,通常需要将一个阵列完全放在一个阵列中 段,只需比较段中的偏移量;这意味着如果
a
b
是两个任意指针,您可能会得到
!(a
但不是
a==b
。在这种情况下,编译器必须提供 针对指针的
std::less
等的专门化(可能) 从指针提取段和偏移量,并执行某种操作 操纵它们

编辑:

对值得提及的其他事物:也许:C++中的保证 标准只适用于标准C++,或者在这种情况下,指针获得 从标准C++。在大多数现代系统上,很容易

mmap
同一个文件指向两个不同的地址范围,并有两个指针
p

q
,它们比较不相等,但指向同一个对象。

我认为在这次讨论中缺少了一个更深层次的概念,那就是指针起源的概念

原则上,您一般不能比较指针,但应该能够比较来自同一个指针(通过算术运算)的指针。 例如,来自黑盒的指针(如对
new
的不同调用)无法可靠地进行比较。 (这里的比较适用于排序,但我想严格来说,在这种情况下,平等也是定义不清的,我不确定。这将涵盖上面的
mmap
案例。)

因此,这里是我尝试的一个(相当无用但概念性的)答案:指针的比较是顺序运算符适用范围内的总顺序(即,当它不是未定义时)。 好的一面是,继续比较属于/来自同一分配或单个块的指针。毕竟,如果
T*p2=p1+1,它必须保持
p2>p1

这类似于C++中容器迭代器的情况,如果两个迭代器来自不同的容器,比较它们就没有意义了。


编辑:肖恩家长对这个问题的看法。释义 (1) 您只能比较相同容器的指针[我认为这太强了,除了
std::vector
]。 (2) 对指针使用
std::less
,因此它仅用于“表示”(例如放入
std::set
)。 (3) 一些编译器会抱怨比较(void?)指针。(我认为这很好,因为void*没有算术)



一些相关材料:

这不是因为虚拟内存提供了线性地址空间才起作用吗?嗯,我不知道以这种方式比较指针是非法的。@R.MartinhoFernandes:很公平。如果您想要一个更具体的问题,请考虑这个变化:“是否可以在指针不形成全局、总顺序的目标上实现标准库?”@哈罗德,分段架构,16位80x86,例如。可以想象,编译器在等中仅使用远指针的偏移量部分。假设没有对象跨越段边界,但小于等,则可以使用完整的20位seg:offset。@Rook:imho比较指针通常不非法,但通常未定义。确定,那么问题是:这个任意的总顺序能与
@Kerrek的子对象顺序兼容吗?不,我从来没有见过这样的要求