在 c++ 中拥有一组结构体的正确方法是什么?

What is the right way to have a set of structs in c++?

提问人:Yur3k 提问时间:2/24/2020 最后编辑:Yur3k 更新时间:12/17/2020 访问量:199

问:

我需要一组自定义结构,以便能够使用最小的给定参数快速检索实例。但是,我发现 std::set 认为某些实例是相同的,即使它们具有不同的值。这是我的示例程序:

#include <set>
#include <iostream>

struct S
{
    int foo, bar;
    S(int foo, int bar): foo(foo), bar(bar) {}
};

inline bool operator<(const S& a, const S& b)
{
    return a.foo < b.foo;
}

int main()
{
    std::set<S> baz;
    baz.emplace(1, 2);
    baz.emplace(1, 3);
    std::cout << baz.size();

    return 0;
}

此程序打印 1

std::set 认为 和 是相同的。我猜这是因为在比较它们时没有使用。但是我需要集合来保留这两个元素,我该如何解决这个问题?S(1, 2)S(1, 3)bar

编辑:我觉得我没有正确陈述我的问题:我想保留不完全相同但对我不起作用的实例,因为我不希望容器中存在相同的实例std::multiset

解决方案:我想我明白出了什么问题。我假设如果 2 个元素都为真,则会导致未定义的行为。但是 std::set 会检查这一点,因此它会删除其中一个元素。对我来说,最好的解决方案是修改比较器,使其包括 .a < bb < abar

C++ 设置 std

评论

0赞 Algirdas Preidžius 2/24/2020
我知道在我们公司,我看到用于此目的。但我不知道这是否是“正确”的方式。memcmp
2赞 Daniel Jour 2/24/2020
@AlgirdasPreidžius....呃,最好不要。填充字节呢?memcmp
1赞 walnut 2/24/2020
您能否详细解释一下您的问题到底是什么?你差不多自己回答了。这些实例被视为等效的,因为在比较中不考虑,并且不保留等效元素。您到底需要回答什么?到目前为止,您对答案的评论似乎表明您有一些额外的理由不包含在比较中或改用。请在问题中解释这些内容。Sbarstd::setbarstd::multiset
0赞 Algirdas Preidžius 2/24/2020
@DanielJour我只是说我在现有代码中看到了这一点。如果我没记错的话:它主要是为 POD 结构完成的。所以我想填充不是什么大问题。主要。。
0赞 walnut 2/24/2020
@Yur3k 请准确定义“不完全相同”的意思。您是否可能用于其他用途,这就是您不想修改它的原因?operator<std::set

答:

1赞 ChrisMM 2/24/2020 #1

如果两者都是唯一的,那么你可以修改你的 以使用这两个变量,如下所示:foobarSoperator<

inline bool operator<(const S& a, const S& b)
{
    if ( a.foo == b.foo )
       return a.bar < b.bar;
    return a.foo < b.foo;
}
3赞 Aykhan Hagverdili 2/24/2020 #2

发生这种情况是因为您只比较 ,如果等价,则对象被视为等价。 只保留一个等效值。如果使对象唯一,则包含在比较中,否则,如果您仍想保留两个(等效)值,请使用 .两者都是有效的解决方案,具体取决于您要执行的操作。foofoostd::setbarbarstd::multiset

评论

0赞 Yur3k 2/24/2020
这 2 个解决方案显然有效,但我不需要在比较中使用,如果我只是放在那里,编译器可能会对其进行优化。barbar
0赞 Aykhan Hagverdili 2/24/2020
@Yur3k你想比较还是不比较?我不清楚。bar
0赞 Yur3k 2/24/2020
在这种情况下,@Axyxan并不重要bar
0赞 Aykhan Hagverdili 2/24/2020
你想要什么行为?为什么不是您要找的解决方案?multiset
0赞 Felipe Matos Mendes 2/24/2020 #3

您可以尝试使用 http://www.cplusplus.com/reference/set/multiset/std::multiset

3赞 DevSolar 2/24/2020 #4

如果它们具有相同的实例,则不会考虑相同的实例,而是您自己的。std::setSfoooperator<

因此,您必须:

  • 更改 ur(这也会影响排序),或者operator<
  • 为您的集合使用不同的比较器(第二个类型参数),或者
  • 将 your 更改为 be fit for 并使用不同的参数(或者您得到的最小元素)。operator<std::setComparestd::sort

底线是,如果您想要不同的比较功能(或其他任何功能),则需要提供不同的功能。std::sortstd::set

由于你没有真正说明为什么你的外表是这样的(没有考虑),所以很难说什么符合你的意图。operator<S::bar

2赞 Yksisarvinen 2/24/2020 #5

简化一点,插入时比较两个元素两次:std::set

  1. a < b
  2. b < a

如果 1.是 ,然后在排序中先行。
否则,如果 2.是 ,然后走在 之前。
Else(两者都是 ),并且是等价的。
trueabtruebafalseab

由于 和 根据 你的定义 ,它们被认为是等价的并且失败。S{1, 2} < S{1, 3} == falseS{1, 3} < S{1, 2} == falseoperator <std::set::emplace

1赞 Daniel Jour 2/24/2020 #6

也许作为对其他答案的补充:

std::set保留一个排序的集合,并使用 创建的 -relation 对元素进行排序。<operator<

所以给定两个对象和......如果 ,则既不是 “小于 ”,也不是 “小于 ”。因此 - 然而,从排序顺序的角度来看。ab! (a < b)! (b < a)abbaa == b