14

比较指向不相关对象的指针有未指定的结果。

这似乎表明该程序可能具有未定义的行为,至少因为我们不能保证对键类型进行严格的弱排序:

#include <map>

int main()
{
    int x = 0, y = 1;
    bool arbitrary = false;

    std::map<int*, bool> m{
       {&x, arbitrary},
       {&y, arbitrary}
    };
}

那么,更一般地说,我们可以说带有指针键的映射是一个危险的*命题吗?还是我们可以在这里依靠一些特殊的规则?

* 从学术上讲,就是;实际上,我不知道主流实现实际上会在比较任意指针时引发地狱。

4

4 回答 4

17

是的,因为std::map默认比较运算符是std::less,与标准比较运算符不同,它是完全为指针类型定义的。

[比较#2]

对于模板less、greater、less_equal 和greater_equal,任何指针类型的特化都会产生与实现定义的严格指针总顺序一致的结果([defns.order.ptr])。

[defns.order.ptr]中定义了实现定义的严格的指针总顺序

实现定义的对所有指针值的严格总排序,使得排序与内置运算符 <、>、<=、>= 和 <=> 施加的部分顺序一致

于 2020-01-05T18:49:11.500 回答
8

std::less(默认比较器std::map)对指针有特殊处理,允许:

任何指针类型的特化std::less都会产生严格的总顺序,即使内置operator<没有。

关于

我们可以说带有指针键的地图是一个危险的命题吗?

所以总体来说没问题。

应使用const char*密钥采取额外的预防措施:

我们比较指针而不是字符串内容(主要是初学者的混淆)。

具有相同内容的 C 字符串文字不保证相等:

"literal" == "literal"; // Not guaranteed
"literal" < "literal"; // false .. or true
于 2020-01-05T18:49:40.007 回答
2

std::map使用std::less对指针类型有专门化的:

任何指针类型的 std::less 特化都会产生严格的总顺序,即使内置的 operator< 没有。该指针类型的 std::less、std::greater、std::less_equal 和 std::greater_equal 特化之间的严格全序是一致的,并且也与相应的内置运算符强加的偏序一致(<、>、<= 和 >=)。

对于更具体的描述,我给你留下 2 个链接:

std::less 第一个链接

std::less 第二个链接

于 2020-01-05T19:01:12.393 回答
1

那是; 实际上,我不知道主流实现实际上会在比较任意指针时引发地狱。

取决于地狱是什么意思。地狱不仅仅是立即崩溃或用随机数据扰乱内存。它可能会给应该是确定性函数的结果带来不确定的结果。

众所周知,GCC 可以优化已知指向不同完整对象 A 和 B 的相关(虚拟)(子)对象的对象的指针比较:任何&A基于. 我不知道是否在 C 或 C++ 中观察到了这种情况,但您的问题几乎是 C/C++(也适用于)。&B&A+1qsort

也就是说,指针比较的结果将取决于指针的已知来源。这意味着根据优化级别、内联上下文、翻译单元等,比较可能会给出不同的结果。

所以是的,如果您进行这些指针比较,它至少可以在流行编译器的某些版本上崩溃。

你不这样做不是std::map用术语定义的,operator<而是用术语定义的std::less

于 2020-01-05T19:04:55.813 回答