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

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

本文关键字:结构 方法 是什么 一组 c++ 拥有      更新时间:2023-10-16

我需要一组自定义结构,以便能够快速检索具有最小给定参数的实例。但是,我发现 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 个元素a < bb < a都是真的,则会导致未定义的行为。但是 std::set 会检查这一点,因此它会删除其中一个元素。对我来说,最好的解决方案是修改比较器,使其包括bar

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

如果S具有相同的foo,则认为的实例不是std::set,而是您自己的operator<

因此,您必须:

  • 更改operator<(这也会影响排序),或
  • 为您的集合使用不同的比较器(第二个类型参数),或
  • 更改operator<以适合std::set,并为std::sort使用不同的Compare参数(或者获得最小的元素)。

底线,如果你想为std::sort(或其他)和std::set提供不同的比较功能,你需要提供不同的功能。

由于您没有真正指定为什么您的operator<看起来像这样(不考虑S::bar),因此很难说什么符合您的意图。

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

  1. a < b
  2. b < a

如果 1. 是true,则a在排序中先于b
否则如果 2.是true,那么b先于a
否则(两者都是false),ab是等价的。

由于S{1, 2} < S{1, 3} == falseS{1, 3} < S{1, 2} == false根据您对operator <的定义,它们被认为是等价的,std::set::emplace失败。

如果foobar都使S唯一,则可以修改operator<以使用这两个变量,如下所示:

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

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

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

所以给定两个对象ab...如果! (a < b)! (b < a),那么a既不比b"少",也不b"小于"a。因此a == b- 然而,从排序顺序的角度来看。

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