void
void

Reputation: 358

Adding dynamic entries in c++ map

I know this may be a silly question but I'm new to c++ and I could not find answer to my question.

I'm using STL std::map to maintain a list of subscriptions and their remote server IPs and PORTs. The number of servers may vary from subscription to subscription. If the number of server is 2 for a subscription then there would be 2 IP addresses and 2 ports entries for that subscription. If 1 server then 1 IP and 1 PORT.

std::map<std::string, SubscriptionInfo> sub_list;

struct ServerInfo {
    u_int32_t        ip;
    u_int16_t        port;
};

struct SubscriptionInfo {
    u_int64_t        subscriptionId;
    int              no_of_servers;
    ServerInfo       *remote;
};

I have the subscription related info in form of c struct from where I can copy the the data to map entry. However, I'm not sure how can I add and delete an entry to/from map by considering the above. Is it possible with map at all or are there other alternatives?

Upvotes: 2

Views: 7302

Answers (1)

PaulMcKenzie
PaulMcKenzie

Reputation: 35440

As my comment suggested, you should strive to not use pointers where they're not necessary, such as ServerInfo *remote; and simply use std::vector:

#include <vector>
#include <map>
#include <string>
#include <cstdint>

struct ServerInfo {
    uint32_t        ip;
    uint16_t        port;
    ServerInfo(uint32_t io_ = 0, uint16_t port_= 0) : 
               ip(ip_), port(_port) {}
};

struct SubscriptionInfo {
    uint64_t        subscriptionId;
    std::vector<ServerInfo> remote;
    SubscriptionInfo(uint64_t val = 0) : subscriptionId(val) {}
};

I updated the SubscriptionInfo to add a constructor that takes the subscriptionId.

Once you have this, adding an existing key and subscription info can be done using std::map::insert:

int main()
{
    std::map<std::string, SubscriptionInfo> sub_list;

    // insert an item into the map.  If already existing, return
    // the iterator to the existing item
    auto iter = sub_list.insert({"1",                  // string
                                SubscriptionInfo(1)}). // subscription info
                                first; // item that was inserted, or
                                       // existing item if already in map.

    // push back a new ip and port into the vector.
    (*iter).second.remote.push_back({ 100,18 });  // add IP and port 18
}

So basically we used std::map::insert to insert a new item into the map. The return value of std::map::insert returns a std::pair, where the first of this pair is the iterator to the item that was inserted, or if already existed in the map, an iterator to the already existing map entry.

That's why we don't have to check if the item exists or not -- all we need to do is call push_back on the remote member since we're going to get back an iterator to the new or existing entry on insert (note that the map itself stores its entries as std::pair<key_type, value_type>, so we want the second of this pair to get the SubscriptionInfo instance).

Also note that we do not need a separate member variable to keep track of the number of servers, as remote.size() returns the number of entries in the vector. Having extraneous variables such as no_of_servers increases the chance that bugs occur due to not manually updating this variable whenever items are added or removed from the vector. Instead, always use std::vector::size() to get you the correct amount.

To delete an entry, all you need is the key value, and the entry is deleted by calling the std::map::erase() function:

    sub_list.erase("1"); // removes key "1" and the data associated with it

Edit: If you're using a compiler that is not C++ 11 compliant, the following changes should be made to the call to insert:

    typedef std::map<std::string, SubscriptionInfo> MapStringToSub;
    //...
    // insert an item into the map.  If already existing, return
    // the iterator to the existing item
    MapStringToSub::iterator iter = sub_list.insert(std::make_pair("1",  // string
                                SubscriptionInfo(1))). // subscription info
                                first; // item that was inserted, or
                                       // existing item if already in map.

    // push back a new ip and port into the vector.
    (*iter).second.remote.push_back(ServerInfo(100,18));  // add IP and port 18

Upvotes: 6

Related Questions