如果对象尚未在集合中,则创建该对象

时间:2016-12-12 22:41:13

标签: c++

有一组指向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`. */
}

2 个答案:

答案 0 :(得分:1)

c ++ 14支持采用任意类型的

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;
}

像那样设置它。然后特殊构造函数仅用于创建 一个廉价的查询对象。为了一点额外的安全性,我们包装断言失败 围绕其他成员,所以部分构造的对象不能 用于其他任何事情。

应该强调的是,这是糟糕的设计。真正的答案是使用 键/值对,如果是内存,则将键从对象中取出 要求。但有时其他压力会造成糟糕的设计,这就是你的答案。