2016-12-08 2 views
0

これは愚かな質問かもしれませんが、私はC++を初めて使ったので、私の質問に答えが見つかりませんでした。C++マップでダイナミックエントリを追加する

私はSTL std :: mapを使用して、サブスクリプションとそのリモートサーバーIPとPORTのリストを維持しています。サーバーの数は、サブスクリプションごとに異なる場合があります。サブスクリプションのサーバ数が2の場合、そのサブスクリプションには2つのIPアドレスと2つのポートエントリがあります。 1つのサーバーに1つのIPと1つのポートがある場合。

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; 
}; 

サブスクリプション関連の情報は、データをマップエントリにコピーすることができる構造体の形式です。しかし、上記を考慮してどのようにエントリを追加/削除することができないのか分かりません。地図でも可能か他の選択肢がありますか?

+6

ドロップ 'ServerInfo *'と 'のstd ::ベクトルを'使用しています。そして、 'no_of_servers'も離れます。ベクトルは独自のサイズを知っているからです。 – PaulMcKenzie

+1

あなたの 'SubscriptionInfo'の中で' std :: vector 'を使います。他の方法が見つからない限り、ポインタを使用しないことを常にお勧めします。 –

答えて

2

私のコメントが示唆したように、このようなServerInfo *remote;として、彼らは必要じゃないポインタを、使用しないように努力し、単にstd::vector使用する必要があります。subscriptionIdを取るコンストラクタを追加するために、私はSubscriptionInfoを更新

#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) {} 
}; 

あなたがこれをしたら、既存のキーおよびサブスクリプション情報が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(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({ 100,18 }); // add IP and port 18 
} 

だから、基本的に私たちがマップに新しい項目を挿入するためにstd::map::insertを使用。 std::map::insertの戻り値は、std::pairを返します。このペアのfirstは、挿入されたアイテムのイテレータまたは既に存在する場合は、既存のマップエントリのイテレータです。

そのため、アイテムが存在するかどうかを確認する必要はありません。remoteメンバーのpush_backに電話する必要があります。これは、新しいエントリまたは既存のエントリへのイテレータを取得するためです。 insert(マップ自体はstd::pair<key_type, value_type>というエントリを格納するので、このペアのsecondSubscriptionInfoインスタンスを取得します)。

remote.size()はベクトルのエントリ数を返すので、サーバーの数を追跡するために別のメンバ変数は必要ありません。 no_of_serversのような無関係の変数を持つと、アイテムがベクトルに追加または削除されるたびにこの変数を手動で更新しないためにバグが発生する可能性が高くなります。代わりに、正しい金額を得るために常にstd::vector::size()を使用してください。

エントリを削除するには、あなたが必要とするすべてはkey値であり、エントリはstd::map::erase()機能を呼び出すことによって削除されます。

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

編集を:あなたはC++ 11に準拠していないコンパイラを使用している場合、次の変更が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 
+0

詳細な説明をありがとう!さて、マップとベクトルを使ってどうすれば実現できるのか理解しています。 –

+0

ここでは、次のように使用しています: for(i = 0; i < sub_data-> no_of_svrs; i ++){ (* itr).second.remote.push_back({sub_data-> remote [i] .r_ip、 sub_data-> remote [i] .r_port}); } ' コンパイル中に次のエラーが発生しました: エラー: '{'トークンの前に予期した一次式 –

+0

標準のC++ 11コンパイラを使用していますか?構文は、ブレースイニシャライザを使用しており、03または1998年のコンパイラには存在しません。 – PaulMcKenzie

関連する問題