提问人:Yur3k 提问时间:2/24/2020 最后编辑:Yur3k 更新时间:12/17/2020 访问量:199
在 c++ 中拥有一组结构体的正确方法是什么?
What is the right way to have a set of structs in c++?
问:
我需要一组自定义结构,以便能够使用最小的给定参数快速检索实例。但是,我发现 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 < b
b < a
bar
答:
如果两者都是唯一的,那么你可以修改你的 以使用这两个变量,如下所示:foo
bar
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;
}
发生这种情况是因为您只比较 ,如果等价,则对象被视为等价。 只保留一个等效值。如果使对象唯一,则包含在比较中,否则,如果您仍想保留两个(等效)值,请使用 .两者都是有效的解决方案,具体取决于您要执行的操作。foo
foo
std::set
bar
bar
std::multiset
评论
bar
bar
bar
bar
multiset
您可以尝试使用 http://www.cplusplus.com/reference/set/multiset/std::multiset
如果它们具有相同的实例,则不会考虑相同的实例,而是您自己的。std::set
S
foo
operator<
因此,您必须:
- 更改 ur(这也会影响排序),或者
operator<
- 为您的集合使用不同的比较器(第二个类型参数),或者
- 将 your 更改为 be fit for 并使用不同的参数(或者您得到的最小元素)。
operator<
std::set
Compare
std::sort
底线是,如果您想要不同的比较功能(或其他任何功能),则需要提供不同的功能。std::sort
std::set
由于你没有真正说明为什么你的外表是这样的(没有考虑),所以很难说什么符合你的意图。operator<
S::bar
简化一点,插入时比较两个元素两次:std::set
a < b
b < a
如果 1.是 ,然后在排序中先行。
否则,如果 2.是 ,然后走在 之前。
Else(两者都是 ),并且是等价的。true
a
b
true
b
a
false
a
b
由于 和 根据 你的定义 ,它们被认为是等价的并且失败。S{1, 2} < S{1, 3} == false
S{1, 3} < S{1, 2} == false
operator <
std::set::emplace
也许作为对其他答案的补充:
std::set
保留一个排序的集合,并使用 创建的 -relation 对元素进行排序。<
operator<
所以给定两个对象和......如果 和 ,则既不是 “小于 ”,也不是 “小于 ”。因此 - 然而,从排序顺序的角度来看。a
b
! (a < b)
! (b < a)
a
b
b
a
a == b
评论
memcmp
memcmp
S
bar
std::set
bar
std::multiset
operator<
std::set