使用包含自己的键的类的STL容器

时间:2014-08-25 15:11:49

标签: c++ map stl unordered

我有 对象 ,可以 通过名称 标识,我想放置它在其中一个 STL容器

class MyClass {
public:
    //getters and setters, other functions
private:
    std::string name;
    //other member variables
};

所以起初我认为 类似地图的结构 的使用在我的情况下是无关紧要的,因为在这些结构中,标识符(键)与阶级本身。使用地图我必须返回名称变量并将其复制到“外部”类(浪费内存和不合逻辑,破坏OOP规则)。

我的下一个镜头是使用 类似于设置的结构 。在这种情况下,我只有关键字段,我加载整个对象。使用这种方法我必须重载我的&lt;,&gt;和==运算符,以便将对象用作键。如果我使用unordered_set,我甚至可以为散列创建一个仿函数,它工作得很好。这里的问题是我不能像使用地图一样使用容器功能。这是有效的mapInstance.find("example"),而不是setInstance.find("example")。我必须创建一个成员变量name设置为“example”的对象,并将其传递给find()函数。此解决方案的问题是我班级中的其他成员变量重复且未使用。我甚至尝试重载&lt;,&gt;和std::stringMyClass类的==运算符,如果我像stringInstance < MyClassInstance一样使用它们,它们工作正常,但容器函数不可用(我甚至尝试重载函数来使用一个没有成功的字符串。)

您能否以简单的方式(或某种方式)向我推荐,如何使用std::setstd::map(或许其他人)解决此问题? 在std::map中,密钥不能作为参考(据我所知),我不知道如何使用std::set来解决它。

注意: 将指针存储在map的关键字段中的问题是,如果我们改变主意并使用unordered_map而不是map,哈希将根据指针计算,而不是基于字符串(哈希函数可以被覆盖,但对于一个简单的任务来说似乎非常复杂)。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

您应该问问自己对容器的要求是什么。

需要考虑的事项是:

  • 容器中通常有多少个对象
  • 内存限制是什么
  • 搜索对象的频率和可接受的复杂程度?

std :: map有一些可能与你的类冲突的要求。例如。将元素添加到地图后,不允许更改密钥。但是,您的班级可能每次都更改名称。从这个考虑,应该很清楚std :: map不能使用对字符串的引用作为键。

在最简单的情况下,您可以考虑使用带有谓词的std::liststd::find_if来检查特殊名称。这将具有O(n)复杂性。

答案 1 :(得分:1)

有时你必须建立在给定的结果上以获得理想的结果。我建议您正在寻找的是适用于您的用例的专用适配器。

这是您可以构建的非常基本的实现。在许多情况下,使用std::vector获得的缓存位置将比使用提供类似功能集的标准容器提供更好的性能。

给出一个简单的类型和一些辅助操作符:

struct Obj
{
   int key;
   std::string name;
};

bool operator<(const Obj& lhs, const Obj& rhs)
{
   return lhs.key < rhs.key;
}

bool operator==(const Obj& lhs, int rhs)
{
   return lhs.key == rhs;
}

bool operator<(const Obj& lhs, int rhs)
{
   return lhs.key < rhs;
}

我们可以设计一个简单的flat_map类,它提供了地图的基本复杂性保证,但是可以满足您按键查找对象的要求,而无需构建值类型(就像您需要的那样)用一套)。插入提供了更多复杂性,但查找具有相似的复杂性。如果查找发生得更频繁,那么插入(大多数情况下就是这种情况)这可以很好地工作。

class flat_map
{
public:
   using container_type = std::vector<Obj>;

   // insert object into the set
   // complexity varies based on length of container
   void insert(Obj&& obj)
   {
      container_.emplace_back(std::move(obj));
      std::sort(container_.begin(), container_.end());
   }

   // find with O(log N) complexity    
   container_type::iterator find(int key)
   {
      auto it = std::lower_bound(container_.begin(), container_.end(), key);

      if(it != container_.end() && *it == key)
         return it;

      return container_.end();
   }

private:
   container_type container_;
};

使用示例:

int main()
{
   flat_map obj;

   obj.insert({1, "one"});
   obj.insert({2, "two"});
   obj.insert({3, "three"});

   auto it = obj.find(2);

   std::cout << it->key << ' ' << it->name << '\n';
}

您可以以任何您认为合适的方式扩展flat_map适配器。添加所需的重载以满足您的要求,对参数进行模板化(分配器,比较,存储类型等)。