【发布时间】:2020-10-21 17:05:40
【问题描述】:
假设我有一个定义如下的类
class Foo {
private:
int date;
std::string name;
public:
void setName(std::string a_name){ name = a_name; };
std::string getName(){ return name; };
void setDate(int a_date){ date = a_date; }
int getDate(){ return date; };
struct FooComparator
{
bool operator()(Foo* lhs, Foo* rhs) const { return lhs->getDate() < rhs->getDate(); }
};
}
现在我想创建几个对象 Foo 并将它们放在按日期排序的集合中,所以我这样做了
std::set<Foo *, Foo::FooComparator> entries;
Foo *a = new Foo();
a->setName("A_OBJ");
a->setDate(10);
entries.insert(a);
Foo *b = new Foo();
b->setName("B_OBJ");
a->setDate(1);
entries.insert(b);
Foo *a_2 = new Foo();
a_2->setName("A_OBJ");
a_2->setDate(9);
entries.insert(a_2);
所以这是问题所在,在我的集合中,我有 3 个条目由 date 排序,因为在指针值上检查了唯一性。有没有办法给set 一个自定义相等比较器,这样它就不会插入a_2,因为已经有一个具有该名称的条目?
我知道unordered_set 可以传递自定义散列函数,但我似乎无法找到类似的方法来使用set,因为我需要条目是唯一的并排序unordered_set不是一个选项。
【问题讨论】:
-
您的
operator()应该将参数作为常量引用。指针可以指向任何地方,而引用则保证指向一个对象。 -
更改您的
operator()以比较名称? -
您无需动态分配对象即可将它们放入
std::set。设置插入操作将插入一个副本。您正在将指针的 副本 插入到您的集合中。在互联网上搜索“内存泄漏”。 -
AFAIK,你想要的只能在无序容器中完成。您必须将其包装在自己的包装器中以提供额外的功能。我不得不问,你有理由使用
set<Foo*>而不是set<Foo>? -
对于
set,唯一性/等价关系和排序关系必须“相同”。这只是(预期)实现为二叉搜索树的结果。如果您的set是按日期排序的,那么它不会帮助您按名称强制执行唯一性(除了,正如@Eljay 指出的那样,让您遍历所有Foos 以查看在插入之前是否使用了名称)。如果您需要快速的名称唯一性检查,也许可以尝试使用两个sets,一个名称和一个Foos(按日期排序),您可以在插入之前/插入时检查/更新前者后者?