具有 std::map<T*, U> 的程序具有良好定义的行为吗?

huangapple go评论85阅读模式
英文:

Does a program with std::map<T*, U> have well-defined behaviour?

问题

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

这似乎暗示了这个程序可能具有未定义的行为,至少因为我们无法保证键类型上有严格弱排序:

#include <map>

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

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

更一般地说,我们能否说具有指针键的地图是一个危险的提议?还是我们可以依靠一些特殊规则?

* 从学术角度来看,是这样的;实际上,我不知道任何主流实现会因为比较任意指针而引发问题。

英文:

Comparing pointers to unrelated objects has unspecified results.

That would seem to suggest that this program may have undefined behaviour, at the very least because we cannot guarantee a strict weak ordering on the key type:

#include &lt;map&gt;

int main()
{
    int x = 0, y = 1;
    bool arbitrary = false;
    
    std::map&lt;int*, bool&gt; m{
       {&amp;x, arbitrary},
       {&amp;y, arbitrary}
    };
}

More generally, then, can we say that a map with pointer keys is a dangerous* proposition? Or is there some special rule we can lean on here?

<sup>* Academically speaking, that is; in reality I'm not aware of mainstream implementations that will actually raise hell over comparing arbitrary pointers.</sup>

答案1

得分: 18

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

[comparisons#2]

对于模板lessgreaterless_&#173;equalgreater_&#173;equal,任何指针类型的特化都产生与指针之间的实现定义的严格全序一致的结果([defns.order.ptr])。

实现定义的指针严格全序[defns.order.ptr]中定义为:

所有指针值上的实现定义的严格全序排序,使得该排序与内建操作符<><=>=<=>所施加的偏序一致。

英文:

Yes, because std::map default comparison operator is std::less, which, unlike the standard comparison operator, is completely defined for pointer types.

> [comparisons#2]
>
> For templates less, greater, less_­equal, and greater_­equal, the specializations for any pointer type yield a result consistent with the implementation-defined strict total order over pointers ([defns.order.ptr]).

The implementation-defined strict total order over pointers is defined in [defns.order.ptr] as:

> implementation-defined strict total ordering over all pointer values such that the ordering is consistent with the partial order imposed by the builtin operators <, >, <=, >=, and <=>

答案2

得分: 8

std::lessstd::map的默认比较器)对指针有特殊处理:

任何指针类型的std::less特化都会产生严格的全序,即使内置的operator<不满足此要求。

关于

我们是否可以说带有指针键的映射是一个危险的命题?

总体来说是可以的。

对于const char*键,需要额外的注意:

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

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

"literal" == "literal"; // 不保证相等
"literal" < "literal"; // false .. 或 true
英文:

std::less (default comparer of std::map) has special treatment about pointer allowing that:

> A specialization of std::less for any pointer type yields a strict total order, even if the built-in operator&lt; does not.

And about

> can we say that a map with pointer keys is a dangerous proposition?

So it is fine in general.

Additional precaution should be taken with const char* key:

We compare pointers and not string content (mostly beginner confusions).

C-string literals with same content have no guaranty to be equals:

&quot;literal&quot; == &quot;literal&quot;; // Not guaranteed
&quot;literal&quot; &lt; &quot;literal&quot;; // false .. or true

答案3

得分: 2

std::map 使用了针对指针类型的专用 std::less

> 为任何指针类型的 std::less 专用化产生了一个严格的全序,即使内置的 operator< 不是这样。这个严格的全序在 std::less、std::greater、std::less_equal 和 std::greater_equal 的专用化之间是一致的,对于该指针类型,也与相应的内置运算符 (<、>、<= 和 >=) 引入的偏序一致。

有关更详细的描述,我给你留下了两个链接:

std::less 第一个链接

std::less 第二个链接

英文:

std::map use std::less that have a specialization for pointer type :

> A specialization of std::less for any pointer type yields a strict
> total order, even if the built-in operator< does not. The strict total
> order is consistent among specializations of std::less, std::greater,
> std::less_equal, and std::greater_equal for that pointer type, and is
> also consistent with the partial order imposed by the corresponding
> built-in operators (<, >, <= and >=).

For a more specific description i leave you 2 links:

std::less first link

std::less second link

答案4

得分: 1

依赖于地狱的含义。地狱不仅仅是立即崩溃或使用随机数据混淆内存。它可能会导致本应该是确定性函数的不确定结果。

GCC 以前会优化指针比较,对于已知指向不同完整对象 A 和 B 的相关(虚拟)(子)对象的对象:基于 &amp;A 的任何内容与基于 &amp;B 的任何内容会产生不同的比较结果,甚至是 &amp;A+1,即使地址实际上相同。我不知道这是在 C 还是在 C++ 中观察到的,但你的问题基本上是关于 C/C++ 的(也适用于 qsort)。

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

因此,是的,如果你进行这些指针比较,它可能会在某些流行编译器的至少某些版本上出现问题。

不过,你不需要这样做,因为std::map 不是根据 operator&lt; 定义的,而是根据 std::less 定义的。

英文:

> that is; in reality I'm not aware of mainstream implementations that
> will actually raise hell over comparing arbitrary pointers.

Depends on what hell means. Hell isn't just crashing right away or scrambling memory with random data. It could be giving indeterminate results to what should be a deterministic function.

GCC was known to optimize pointer comparisons on objects known to point to related (virtual) (sub) objects of different complete objects A and B: anything based on &amp;A would compare differently to anything based on &amp;B, even &amp;A+1, even when the address were actually the same. I don't know if that was observed in C or in C++, but your question is pretty much C/C++ (and applies to qsort too).

That is, the result of a pointer comparison would depend on the known origin of a pointer. That mean that depending on optimization level, inlining context, translation unit, etc. a comparison could give different results.

So yes it could break down on at least some versions of a popular compiler if you did these pointer comparisons.

Which you don't as std::map is not defined in term operator&lt; but in term of std::less.

huangapple
  • 本文由 发表于 2020年1月6日 02:45:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/59603086.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定