Using pointers seems reasonable. Here's a suggested API that you could implement:
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_;
};
I think this should be pretty straightforward to implement. You just need to make sure to maintain the following invariant:
w is in widgets_ iff a pointer to it is in widgets_by_*
I think the main pitfall that you'll encounter is making sure is that name and id are not already in widgets_by_* when Insert is called.
It should be easy to make this thread safe; just throw in a mutex
member variable, and some local lock_guards
. Optionally, use shared_lock_guard
in the Get*
methods to avoid contention; this will be especially helpful if your use-case involves more reading than writing.