【发布时间】:2015-08-18 04:09:52
【问题描述】:
(与my previous question相关)
在 QT 中,QMap documentation 表示:
QMap 的键类型必须提供
operator<()指定总顺序。
但是,在qmap.h 中,他们似乎使用类似于std::less 的东西来比较指针:
/*
QMap uses qMapLessThanKey() to compare keys. The default
implementation uses operator<(). For pointer types,
qMapLessThanKey() casts the pointers to integers before it
compares them, because operator<() is undefined on pointers
that come from different memory blocks. (In practice, this
is only a problem when running a program such as
BoundsChecker.)
*/
template <class Key> inline bool qMapLessThanKey(const Key &key1, const Key &key2)
{
return key1 < key2;
}
template <class Ptr> inline bool qMapLessThanKey(const Ptr *key1, const Ptr *key2)
{
Q_STATIC_ASSERT(sizeof(quintptr) == sizeof(const Ptr *));
return quintptr(key1) < quintptr(key2);
}
他们只是将指针转换为quintptrs(这是uintptr_t 的QT 版本,即能够storing a pointer 的无符号整数)并比较结果。
以下类型指定了一个无符号整数类型,其属性是任何指向 void 的有效指针都可以转换为该类型,然后转换回指向 void 的指针,结果将与原始指针进行比较:
uintptr_t
你认为qMapLessThanKey() 在指针上的这种实现好吗?
当然,整数类型有一个全序。但我认为这还不足以断定这个操作定义了指针的总顺序。
我认为只有当 p1 == p2 暗示 quintptr(p1) == quintptr(p2) 时它才是正确的,AFAIK 没有指定它。
作为这种情况的反例,想象一个使用 40 位指针的目标;它可以将指针转换为quintptr,将 40 个最低位设置为指针地址,并使 24 个最高位保持不变(随机)。这足以尊重quintptr 和指针之间的可转换性,但这并没有定义指针的总顺序。
你怎么看?
【问题讨论】:
-
好问题。不过,我想你自己已经回答过了:从指针到整数的转换每次都会产生不同的值(想象
to_int(void * p) { return to_int32(p) + rand() << 40; } -
理论上没问题,但有人知道这样的平台吗?
-
谈到您的示例,如果指针是 40 位但无符号长整数是 64 位,那么断言将触发。
-
@NathanOliver 好点:)
-
@marom 编译器在 x86 上用于实模式和保护模式 segmented memory model。在这种情况下,您完全有标准的限制。
标签: c++ qt pointers undefined-behavior partial-ordering