vk-code
vk-code

Reputation: 1098

Correct way to create and manage look up containers

correct way to create look up maps for instances. I have a structure defined Node as follows

struct Node
{
    int32_t id;
    std::string name;
    ...
}

i want to create 2 look up maps, on based on id and another based on name. There are other attributes in the Node which also needs look up maps but those are dynamic so not every Node instance will have a look entry into those additional maps.

with just one look up map I was planning to create something like

typedef std::unoredered_map<int32_t, std::unique_ptr <Node> > NodesById;

I reason being just I can get this deleted by just erase or [id] = new 'overwrite!' operation and don't have to worry about it. But then how can I add the same Node instance to say another map

typedef std::unoredered_map<std::string, std::unique_ptr <Node> > NodesByName;

I cannot put same Node instance into to unique_ptr. So my question is what is the correct way to store Node instances into multiple look up tables and still achieve smart memory management.

Upvotes: 0

Views: 103

Answers (1)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136525

Use boost::multi_index:

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <string>    
#include <cassert>    

struct Node {
    int32_t id;
    std::string name;

    Node(int32_t id, std::string name)
        : id(id)
        , name(move(name))
    {}

    // Just to demonstrate that Node doesn't need to be copyable/moveable.
    Node(Node const&) = delete;
    Node& operator=(Node const&) = delete;
};

namespace mi = boost::multi_index;

using NodeSet = mi::multi_index_container<
      Node
    , mi::indexed_by<
            mi::hashed_unique<mi::member<Node, int32_t, &Node::id>>
          , mi::hashed_unique<mi::member<Node, std::string, &Node::name>>
      >
    >;

int main() {
    NodeSet s;
    s.emplace(1, "Alice");
    s.emplace(2, "Bob");

    assert(s.find(1)->name == "Alice");
    assert(mi::get<0>(s).find(1)->name == "Alice"); // Same as above.
    assert(mi::get<1>(s).find("Alice")->id == 1);
}

Storing by value is more efficient than storing unique_ptr in there. And since NodeSet doesn't require Node to be copyable or moveable it is unnecessary to use unique_ptr here.

Upvotes: 4

Related Questions