有一组指向A
类型的唯一对象的指针,我想创建并在该集合中插入一个新元素,但只有在那里已经没有这样的元素了。
问题是,标准比较器操作现有对象,还有一个尚不存在。这意味着我无法确定对象是否在集合中而不创建对象(或者没有手动迭代整个集合)。
一个显而易见的解决方案是使用包含A
部分的键替换映射集,使A
类型的对象唯一,但它几乎使内存使用量翻倍。这对我来说是不可接受的。
有什么想法吗?
UPDATE 更具体地说,这是一个简化的例子:
class Base { /* members */ };
class Derived : public Base {
static std::set<Derived *> cache;
std::vector<Object *> v;
public:
static Derived *Create(const std::vector<Object *> &v);
/* other members */
};
Derived *Derived::Create(const std::vector<Object *> &v) {
/* Here I need to create and insert a new object of type Derived
into the `Derived::cache`, but only if there is no such object
in the set yet. Objects are uniqued by contents of `v`. */
}
答案 0 :(得分:1)
std::find_if
:
#include <set>
#include <tuple>
#include <memory>
//
// the concept of an Identity - some signature that identifies an object
// uniquely
struct Identity
{
Identity(int v) : v_(v) {}
auto as_tuple() const { return std::tie(v_); }
private:
int v_;
};
bool operator<(Identity const& l, Identity const& r)
{
return l.as_tuple() < r.as_tuple();
}
//
// some object that has an identity
//
struct Thing
{
Thing(Identity i) : ident_(std::move(i)) {}
const Identity& identity() const { return ident_; }
private:
Identity ident_;
};
struct LessThing
{
struct is_transparent {};
bool operator()(const std::unique_ptr<const Thing>& l, const Identity& r) const
{
return l->identity() < r;
}
bool operator()(const Identity& l, const std::unique_ptr<const Thing>& r) const
{
return l < r->identity();
}
bool operator()(const std::unique_ptr<const Thing>& l, const std::unique_ptr<const Thing>& r) const
{
return l->identity() < r->identity();
}
};
int main()
{
std::set<std::unique_ptr<const Thing>, LessThing> myset;
myset.insert(std::make_unique<Thing>(Identity(5)));
myset.insert(std::make_unique<Thing>(Identity(6)));
if (myset.find(Identity(7)) == myset.end())
{
myset.emplace(std::make_unique<Thing>(Identity(7)));
}
}
注1:比较仿函数中is_transparent
类型的定义,以启用此行为。
注意2:请记住,集合的元素是常量。如果密钥比较依赖于集合中指针所指向的对象,那么该数据(或至少其中的标识部分)必须是不可变的。
答案 1 :(得分:0)
您需要调用set :: count。
count然后会调用'&lt;'您传递的对象上的运算符,以及集合中的对象。所以你必须构造一个对象。
但是'&lt;'运营商不需要访问每个字段。大概。如果绝对必须在每个字段上进行比较,那么除了创建查询对象之外没有其他解决方案。但很可能该对象具有您用于快速比较的Id或类似字段。 所以你需要一个特殊的构造函数。
class MyClass
{
int id;
std::vector<int> expensive_member;
friend bool operator < (MyClass const &, MyClass const &);
public:
MyClass(std::vector<int> const &expensivetosetup, int id);
MyClass(int id);
void member() { assert(expensive_member.empty() == false);}
}
bool operator < (MyClass const &a, MyClass const &b)
{
return a.id < b.id;
}
像那样设置它。然后特殊构造函数仅用于创建 一个廉价的查询对象。为了一点额外的安全性,我们包装断言失败 围绕其他成员,所以部分构造的对象不能 用于其他任何事情。
应该强调的是,这是糟糕的设计。真正的答案是使用 键/值对,如果是内存,则将键从对象中取出 要求。但有时其他压力会造成糟糕的设计,这就是你的答案。