Reputation: 358
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
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