C++ 将std::less与nullptr一起使用

C++ 将std::less与nullptr一起使用,c++,c++11,C++,C++11,以下代码段中的断言是否始终有效 std::less<Object *> lessPtr; Object * o = new Object(); assert(lessPtr (o, nullptr) == false); std::lessPtr; Object*o=新对象(); 断言(lessPtr(o,nullptr)=false); 否,空指针相对于任何非空指针的顺序未指定 如果操作数“指向不是同一对象的成员或同一数组的元素或不同函数的不同对象,或者如果其中只有一个为空”,则

以下代码段中的断言是否始终有效

std::less<Object *> lessPtr;
Object * o = new Object();
assert(lessPtr (o, nullptr) == false);
std::lessPtr;
Object*o=新对象();
断言(lessPtr(o,nullptr)=false);

否,空指针相对于任何非空指针的顺序未指定

如果操作数“指向不是同一对象的成员或同一数组的元素或不同函数的不同对象,或者如果其中只有一个为空”,则比较运算符的结果是未指定的

std::less
和friends对此进行了扩展,以指定总顺序,但不指定空指针按该顺序出现的位置。因此可以保证
null
始终大于或小于任何给定的非null指针。但是它没有被指定为小于或大于所有非空指针。

Introduction 这个问题实际上归结为对指针类型使用小于关系运算符(其中一个操作数是
nullptr
)是否会产生“预期”结果;可惜事实并非如此

结果不详

注意:请注意
std::less
保证总订单;这意味着,即使结果在使用函数对象时未指定,它也必须在每次调用时产生相同的未指定值


国际标准()怎么说? 5.9p2关系运算符
[expr.rel]

可以比较指向相同类型的对象或函数的指针(指针转换后),结果定义如下:

  • 如果同一类型的两个指针
    p
    q
    指向同一对象或函数,或者两个指针都指向同一数组的末尾,或者都为空,则
    p=q
    都产生
    true
    pq
    都产生
    false

  • 如果同一类型的两个指针
    p
    q
    指向不同的对象,而这些对象不是同一对象或同一数组元素的成员,或者指向不同的函数,或者如果其中只有一个指针为空,则
    pq
    的结果是未指定的

  • 如果两个指针递归地指向同一对象的非静态数据成员,或指向此类成员的子对象或数组元素,则如果两个成员具有相同的访问控制(第11条)且其类不是并集,则指向后一个声明成员的指针会比较大

  • 如果两个指针指向具有不同访问控制的同一对象的非静态数据成员(第11条),则结果未指定

  • 如果两个指针指向同一union对象的非静态数据成员,则它们的比较相等(如果需要,在转换为
    void*
    之后)。如果两个指针指向同一数组的元素,或者一个指针指向数组末尾以外的元素,则指向下标较高的对象的指针会比较高

  • 未指定其他指针比较

20.8.5p8
比较
[Comparison]

对于模板
更大的
更小的
更大的
更小的
,任何指针类型的专门化都会产生一个总顺序,即使内置操作符
=
没有


那么,标准到底在说什么?

p
的判决是什么?

因为
p
q
不指向同一数组的不同元素(包括超过数组最后一个元素的元素),并且都不指向同一对象的非静态数据成员;执行
p
(和
p>q
)时的结果未指定


这里有一个古老的答案,其中引用了标准中的一句话,即less可能不会像您预期的那样表现为指针:。我怀疑答案是标准并不能保证它,但在实践中应该可以。N3936(C++14)比N3337添加了更强的保证
T * p = new T;
T * q = nullptr;
bool a = p < q;  // unspecified
bool b = p < q;  // unspecified

assert (a == b); // can fire
std::less<T*> comp;

bool a = comp (p, q);  // unspecified
bool b = comp (p, q);  // unspecified

assert (a == b);       // can not fire