【问题标题】:Can you compare nullptr to other pointers for order? Is it always smaller?您可以将 nullptr 与其他指针进行比较吗?它总是更小吗?
【发布时间】:2021-03-18 23:54:52
【问题描述】:

这个问题是基于我发现的用于监视可能的内存泄漏的代码,因此它包含一些您可能不希望在常规程序中看到的代码,例如排序指针。

但是,我看到一个指针被设置为nullptr,然后将该指针与一个最大地址进行比较。 C++ 标准是否保证nullptr 总是小于operator< 的其他指针?

【问题讨论】:

  • “小于其他指针”不同于“与最大地址相比”。您是否好奇他们的比较是否安全?或者,如果比较 nullptr 通常是安全的?
  • 指针比较仅适用于相同数组的元素,或==!=。未指定将指向不在同一数组中的对象的指针与 operator< 进行比较。
  • 如果指针指向同一个数组,您只能比较小于和大于指针。
  • 仅供参考:std::less任何指针类型的 std::less 特化都会产生严格的总顺序,即使内置运算符 虽然,我没有看到关于 nullptr 与任何其他指针相比如何的声明。

标签: c++ comparison-operators pointer-arithmetic nullptr


【解决方案1】:

你能比较一下 nullptr 和其他指针的顺序吗?

不,您不能用指针对nullptr 或其他空指针常量进行有序比较。


对于我的其余答案,我将介绍 “您能否将 具有空值的指针与其他指针进行比较以进行排序?”

是的。但结果是否有用是另一回事。

总是更小吗?

没有。除非另一个操作数也为 null,否则在这种情况下,两个操作数都不能保证比较更大或更小。

标准报价(最新草案):

[expr.rel]

比较不相等的指向对象的指针的结果是按照符合以下规则的偏序来定义的:

  • [不适用]如果两个指针指向同一个数组的不同元素,或其子对象,则需要指向具有较高下标的元素的指针才能比较大。
  • [不适用]如果两个指针指向同一个对象的不同非静态数据成员,或者指向这些成员的子对象,递归地,需要指向后面声明的成员的指针比较大提供这两个成员具有相同的访问控制 ([class.access]),两个成员都不是大小为零的子对象,并且它们的类不是联合。
  • [applies] 否则,两个指针都不需要比较大于另一个。

如果您需要严格的总顺序,您应该使用std::less 来比较指针。 Null 仍然不能保证作为最小值进行比较。

【讨论】:

  • 我没有得到最后一个链接。即使在具有“指针是整数,nullptr 只是 0”的系统上,nullptr 是否最小的问题仍然取决于系统是否将指针视为有符号整数或无符号整数的问题。这很随意;例如我不认为 x86 有一个自然的选择。 (您可以在指针上使用jajg)。
  • @MSalters 这篇文章是关于非零 null 和指针,它们根据类型具有不同的表示形式。 x86 的某些模式是后者的示例,与本主题不太相关。这篇文章还有其他关于非零 null 的示例,我认为它们会影响排序。
  • 我认为你错过了我评论的重点。即使在 x86 上,使用全位零作为 nullptr 并将指针与 jg(跳转更大,有符号)进行比较的编译器也会有许多小于 nullptr 的指针。这作为一种设计非常有意义,例如在经典 Win32 上,这些是指向系统地址空间的指针。大于nullptr 的指针将指向用户地址空间。这就是为什么今天的 Win32 可执行文件有一个“大地址感知”标志 - 它告诉操作系统可执行文件没有做出这样的假设。
  • 我有一个平台,它的可寻址内存位于 0x00000000 和 0x40000000,并使用 0x20000000 作为nullptr。将指针与 < 进行比较会将所有 RAM 指针排序在 nullptr 之前,并将所有 ROM 指针排序在它之后。
  • wiki.osdev.org/Higher_Half_Kernel 提到这不是 x86 特定的。
【解决方案2】:

没有。涉及 nullptr 的小于比较没有指定的行为,虽然它们不涉及未定义的行为,但结果甚至不能保证是一致的。

< 对指针提供的保证非常有限。即使比较两个单独的堆分配对象也不能保证是一致的(因为您需要std::less,它将始终在排序中放置一个空指针somewhere,但不是在标准定义的位置) .最好的说法是,没有指向对象的指针会将 equal 与 nullptr 进行比较。

【讨论】:

  • 在现实生活中,每个编译器都会对指针使用简单的整数比较,因为这是满足要求的最简单方法。
  • 在现实生活中,遵循语言规则几乎总是比猜测什么是安全的更务实。
【解决方案3】:

nullptr 总是小于运算符的其他指针

不,标准不支持nullptr与关系运算符的指针进行比较。

要比较关系运算符的操作数,首先将以下规则应用于两个操作数,即 expr.rel#2

通常的算术转换是在算术或枚举类型的操作数上执行的。 如果两个操作数都是指针,则执行指针转换和限定转换以将它们变为复合指针类型。转换后,操作数的类型应相同。

nullptr 不是指针,而是称为空指针常量。因此,“执行指针转换和限定转换以使其成为复合指针类型”将不适用于它。因此,它违反了,转换后,操作数应具有相同的类型

Clang 给出正确的诊断。由于代码格式不正确,因此谈论结果是什么没有意义。

【讨论】:

  • 如果我们的编译器给出了那个错误,那我就不用问这个问题了。
  • @srefaanv 就我个人而言,我认为 clang 的实现最接近标准要求,并且它给出的诊断更易于阅读。
  • 我同意,这就是我接受您的回答的原因。我只是不能在当前长期运行的项目中使用 clang。我们根据这个问题的答案更改了代码。
猜你喜欢
  • 1970-01-01
  • 2022-11-03
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
相关资源
最近更新 更多