std::set 指针中的虚假 "containment"

spurious "containment" in std::set of pointers

一组指针报告它“包含”一个全新的对象,即使这个对象是刚刚创建的,并且具有与集合中已有的不同的内存地址。

#include <iostream>
#include <set>
#include <vector>

using namespace std;

class foo {
  public:
    int x;
    foo(int x) : x(x) {}
};

int main() {
    vector<foo> my_vector;
    set<foo*, bool (*)(foo*, foo*)> my_set([](foo* left, foo* right) { return left->x < right->x; });

    my_vector.reserve(10);
    for (int i = 0; i < 10; i++) {
        my_vector.emplace_back(i);
        my_set.emplace(&my_vector[i]);
    }
    foo temp(4);
    if (my_set.count(&temp))
        cout << "But why?" << endl;
    return 0;
}

如果 temp 使用范围 [0, 10) 之外的整数初始化,则此行为 不会 发生。就好像整数 x 被用来确定 相等性 ,而不仅仅是优先级/优先级。

我想要的行为是不同的对象(即具有不同的内存位置)总是被视为集合中的不同对象,并且对象的值x 用于对元素进行排序。我如何实现这种行为?谢谢。

std::set中,对于两个值L和R,如果L<RR<L都不相等,则认为它们相等。 "priority/ordering" 和相等没有分开,正如你所想的那样。

How do I achieve this behavior?

使用 std::set 以外的容器。例如,您保持排序的向量。

感谢大家的评论。这是实现所需行为的解决方案:

int main() {
    set<foo*, bool (*)(foo*, foo*)> my_set([](foo* left, foo* right) {
        if (left->x == right->x)
            return std::less<foo*>{}(left, right);
        return left->x < right->x;
    });
    // ....
    return 0;
}

已编辑以反映@Igor Tandetnik 的有用评论!

您可以先在 lambda 中检查是否相等。如果此检查失败,您可以计算顺序关系...