哪些容器存储通过不同标识符访问的对象

Which containers to store objects for access via different identifiers?

本文关键字:标识符 访问 对象 存储      更新时间:2023-10-16

我必须通过几个不同的标识符访问我的对象(来自一个类的多个实例),并且不知道存储从标识符到对象的映射的最佳方法是什么。我充当两个世界之间的"连接器",每个世界都有自己的标识符,我必须使用/支持。如果可能的话,我希望避免使用指针。

第一个想法是将对象放在List/Vector中,然后为每种类型的标识符创建一个映射。很快我就意识到std-container不支持存储引用。

下一个想法是将对象保留在向量中,并将索引放在映射中。这里的问题是,我没有为vector找到index_of,并且只有当没有人使用insert或erase操作时,将索引存储在对象中才有效。

创建对象时唯一的标识符是字符串,出于性能考虑,我不想使用这个字符串作为映射的标识符。

这个问题是最好的解决与指针或谁有一个想法如何处理它?

谢谢

使用指针似乎很合理。以下是您可以实现的一个建议API:

class WidgetDatabase {
 public:
  // Returns true if widget was inserted.
  // If there is a Widget in *this with the same name and/or id,
  // widget is not inserted.
  bool Insert(const std::string& name, int id, const Widget& widget);
  // Caller does NOT own returned pointer (do not delete it!).
  // null is returned if there is no such Widget.
  const Widget* GetByName(const string& name) const;
  const Widget* GetById(int id) const;
 private:
  std::set<Widget> widgets_;
  std::map<std::string, Widget*> widgets_by_name_;
  std::map<int, Widget*> widgets_by_id_;
};

我认为这应该很容易实现。您只需要确保维护以下不变式:

w在widgets_中,如果指向它的指针在widgets_by_*

我认为您将遇到的主要陷阱是确保在调用Insert时名称和id不在widgets_by_*中。

使这个线程安全应该很容易;只要加入一个mutex成员变量,和一些局部的lock_guards。可以选择在Get*方法中使用shared_lock_guard来避免争用;如果您的用例涉及更多的阅读而不是书写,这将特别有用。

您考虑过内存中的SQLite数据库吗?SQL为访问相同的数据提供了多种方法。例如,您的模式可能如下所示:

CREATE TABLE Widgets {
  -- Different ways of referring to the same thing.
  name STRING,
  id INTEGER,
  -- Non-identifying characteristics.
  mass_kg FLOAT,
  length_m FLOAT,
  cost_cents INTEGER,
  hue INTEGER;
}

然后可以使用不同的标识符进行查询:

SELECT mass_kg from Widgets where name = $name

SELECT mass_kg from Widgets where id = $id
当然,SQL允许您做的远不止这些。这将允许您在将来轻松扩展库的功能。

另一个优点是SQL是声明性的,这通常使它更简洁和可读。

在最近的版本中,SQLite支持对同一个数据库的并发访问。随着时间的推移,并发模型变得越来越强大,因此您必须确保了解所使用的版本所提供的模型。最新版本的文档可以在sqlite的网站上找到