【问题标题】:std::map comparing pointersstd::map 比较指针
【发布时间】:2013-01-05 03:35:34
【问题描述】:

如何在下面的示例中实现比较运算符,以使ObjectPair( &a, &b ) 等于ObjectPair( &b, &a )?此外,我将如何使用stdext::hash_map 而不是std::map 来实现这一点?

struct ObjectPair
{
    public:

        ObjectPair( Object* objA, Object* objB )
        {
            A = objA;
            B = objB;
        }

        bool operator<( const ObjectPair& pair ) const
        {
            // ???
        }

        Object* A;
        Object* B;
};

int main()
{
    std::map< ObjectPair, int > pairMap;

    Object a;
    Object b;

    pairMap[ ObjectPair(&a, &b) ] = 1;
    pairMap[ ObjectPair(&b, &a) ]++;    

    /// should output 2
    std::cout<< pairMap[ ObjectPair( &a, &b ) ] << std::endl;

    return 0;
}

【问题讨论】:

  • @Jake223:不,你不应该。 std::map::operator[] 返回对该值的引用。如果没有,那么这段代码甚至无法编译。

标签: c++ map key


【解决方案1】:

您的基本问题是您需要实现operator&lt;,这样它就不能区分a 和b,但对所有不相等的对象返回一致的结果。

最简单的做法可能是对指针进行排序,然后比较它们。类似的东西

bool operator<(const ObjectPair& pair) const {
    // Technically < is unspecified on most object pointers
    // but std::less<T> is guaranteed to have a total ordering
    std::less<Object*> comp;
    Object *ourlow = std::min(a, b, comp);
    Object *ourhigh = std::max(a, b, comp);
    Object *theirlow = std::min(pair->a, pair->b, comp);
    Object *theirhigh = std::max(pair->a, pair->b, comp);
    if (comp(ourlow, theirlow)) return true;
    if (comp(theirlow, ourlow)) return false;
    return comp(ourhigh, theirhigh);
    }
    return false;
}

当然,这是假设Object 不可排序,因此我们只关心指针值是否相同。如果Object 本身有一个排序,那么你应该调用Object::operator&lt;() 而不是仅仅在指针上使用&lt;,即if (*ourlow &lt; *theirlow)


为了使这项工作在std::unordered_map(这是我假设stdext::hash_map 等效的C++11 事物)中工作,那么您需要实现operator== 以及专门化std::hash&lt;&gt; 为您的对象。对于您的专业,您可能只想散列两个指针并组合值(使用按位异或之类的东西)。


附加到这个问题的非常长的评论线程的要点与 C++ 标准关于指针比较的内容有关。即,比较不是同一对象/数组成员的相同类型的两个对象指针会调用未指定的行为。一般来说,这对于具有单一统一内存系统的任何架构(即您可能使用的任何架构)都无关紧要,但符合标准仍然很好。为此,比较已全部更改为使用 std::less&lt;Object*&gt;,因为 C++ 标准保证 std::less&lt;T&gt; 具有总排序。

【讨论】:

  • @KevinBallard:将指针与&lt; 进行比较是未定义的行为,使用std::less&lt;T*&gt; 可以获得明确定义的行为。 (另外,这个答案是不是太复杂了?)为什么不return (a==rhs.a&amp;&amp;b==rhs.b) || (a==rhs.b&amp;&amp;b==rhs.a);
  • @KevinBallard 如果指针不指向相同的内存分配块,则 undefined 未指定。 std::less 的“魔法”是 reinterpret_cast 到 std::intptr_t。无论如何,我要 +1。
  • @KevinBallard: 20.8.5(14) “对于更大、更少、greater_equal 和 less_equal 的模板,任何指针类型的特化都会产生一个总顺序,即使内置运算符 , = 不要。”
  • @KevinBallard:std::less 开始使用标准库编写器的魔法,包括继续前进并了解未定义行为的行为。也就是说,即使我们这些农民不能做出这样的假设,但如果编译器和库编写者愿意,他们可以(即确保他们运行的平台做正确的事情)。
  • @KevinBallard:请注意,您仍然可以使用std::max(和亲属)并将comp 作为第三个参数传入。遗憾的是两参数 std::max 使用内置 &lt; 而不是使用 std::less&lt;T&gt; 委托给三参数重载。没错,实际上 OP 永远不会注意到。
猜你喜欢
  • 1970-01-01
  • 2012-04-27
  • 2017-01-19
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
相关资源
最近更新 更多