【问题标题】:Are pointers allowed as keys in ordered STL containers?是否允许指针作为有序 STL 容器中的键?
【发布时间】:2011-02-06 12:07:14
【问题描述】:

C++ 标准中有 this other question asking about how comparing pointers is supposed to be interpreted

所以我想知道 C++ Std 对在有序标准库 (STL) 容器中使用指针作为键有什么看法——即是否允许拥有

std::map<T1*, T2>

这是由于std::lessbuiltin operator < 的规范造成的吗?

【问题讨论】:

标签: c++ pointers standards containers


【解决方案1】:

是的,因为它使用了std::less,即使< 没有,它也是产生总订单所必需的。 (< 将被允许将来自不同序列的不同指针视为相等,如果您插入来自不同序列的指针,这将导致 map 等的奇怪行为。

【讨论】:

  • 措辞略有不同:从评论中引用sellibitze到下面的答案:“......在关联容器中使用指针作为键是安全的。但这与less-无关than 运算符,因为 std::less 是这些容器的默认比较器,并且 C++ 为 std::less 提供特殊保证,以防 T 是指针类型。..."
【解决方案2】:

我想补充另一个不这样做的理由。如果您以这种方式使用指针,并且碰巧遇到了依赖于容器元素顺序的错误,那么将很难找到。即使你的程序看起来是完全确定的,但它不会。容器中元素的顺序取决于内存分配器使用的算法,这完全不受您的控制。如果在不重新启动程序的情况下多次运行相同的示例,一些可能会失败,而另一些会成功。

这是痛苦经历的声音。我曾经用一个调试器项目做过这个,我有一个充满 C++ 符号的容器。当我需要对符号进行排序时,我最终得到了不同的符号,但它们具有相同的名称(考虑重载函数)并且在所有其他方面都相同。因此,在这种情况下,我将它们作为最后的手段通过符号对象的地址进行比较。我遇到了几个显然是非确定性的错误,其中非确定性是由这种现象引起的。有时,重现问题需要 10 或 15 次以上的尝试。我最终花时间消除了按地址排序,从长远来看,这为我省去了很多麻烦。

话虽如此,我不会说我最近没有这样做。但每次我这样做我都觉得这是一个错误。

【讨论】:

    【解决方案3】:

    “它们可能有效但无效”是我会给出的答案。

    显然存在您提出的可比性问题,但您不想这样做的原因是因为“vanilla”指针缺乏引用管理。对象不从容器中移除就很容易被删除,导致下次访问时指针无效和访问冲突。

    【讨论】:

    • 这不一定有效——unique_ptr 或 shared_ptr 之类的东西很可能提供基于底层指针的比较运算符。
    【解决方案4】:

    是的。指针可通过 operator

    如果指针不指向同一数组的元素或同一对象中的元素,则 c++ 标准表示行为未指定 [expr.rel]。

    标准说未指定的行为意味着它的实现已定义 [defns.unspecified]。

    如果您的编译器保证严格的弱指针顺序,您可以使用任何带有关联容器的指针。

    大多数编译器通过比较内存地址来进行指针比较。在大多数架构上,这种比较形成严格的弱顺序。

    因此使用指针作为键是安全的。

    【讨论】:

    • 仅当它们指向同一个数组的元素时。 c++ 标准为 std::less 提供了更强的保证,这是有序关联容器的默认设置
    • @sellibitze:指针与数组无关。指向不同数组元素的指针不太可比。
    • @joke:不,标准不允许将任意指针与< 进行比较。
    • C++ 标准对此没有任何保证。但很有可能,它在大多数实现中都能满足您的需求。仅供参考:我没有投反对票。但也许我应该——考虑到这个答案是错误的并且你忽略了批评。
    • §5.9/2,第二个要点:“如果相同类型的两个指针 p 和 q 指向不同的对象,这些对象不是同一对象的成员或同一数组的元素或不同的函数,或者如果其中只有一个为空,则 pq, p=q 的结果是未指定的。”
    猜你喜欢
    • 1970-01-01
    • 2012-12-14
    • 2013-03-13
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多