2016-12-08 2 views
0

Ich weiß, dass dies eine dumme Frage sein kann, aber ich bin neu in C++ und ich konnte keine Antwort auf meine Frage finden.Hinzufügen von dynamischen Einträgen in C++ Karte

Ich benutze STL std :: map, um eine Liste von Abonnements und ihre Remote-Server IPs und PORTs zu pflegen. Die Anzahl der Server kann von Abonnement zu Abonnement variieren. Wenn die Anzahl der Server 2 für ein Abonnement ist, dann gibt es 2 IP-Adressen und 2 Ports für dieses Abonnement. Wenn 1 Server dann 1 IP und 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; 
}; 

Ich habe die Abonnement bezogenen Informationen in Form von C-Struktur von wo ich die Daten zum Karteneintrag kopieren kann. Ich bin mir jedoch nicht sicher, wie ich einen Eintrag zu/von der Karte hinzufügen und löschen kann, indem ich das Obige in Betracht ziehe. Ist es mit Karte überhaupt möglich oder gibt es andere Alternativen?

+6

Drop the '' Serverinfo * und verwendet ein 'std :: vector ': die folgenden Änderungen sollen den Aufruf insert gemacht werden. Dann geht auch der 'no_of_servers' weg, da der Vektor seine eigene Größe kennt. – PaulMcKenzie

+1

Verwenden Sie 'std :: vector ' in Ihrem 'SubscriptionInfo'. Ziehen Sie es immer vor, keine Zeiger zu verwenden, solange keine andere Alternative gefunden werden kann. –

Antwort

2

Wie mein Kommentar vorgeschlagen, sollten Sie versuchen, keine Zeiger zu verwenden, wo sie nicht notwendig sind, wie ServerInfo *remote; und einfach verwenden 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) {} 
}; 

ich die SubscriptionInfo aktualisiert einen Konstruktor hinzufügen, die die subscriptionId nimmt .

Sobald Sie diese haben, können einen vorhandenen Schlüssel und Abonnement info Hinzufügen std::map::insert getan werden:

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 
} 

wir std::map::insert Also im Grunde verwendet, um ein neues Element in die Karte einzufügen. Der Rückgabewert std::map::insert gibt std::pair zurück, wobei first dieses Paares der Iterator für das Element ist, das eingefügt wurde, oder, falls bereits in der Map vorhanden, ein Iterator für den bereits vorhandenen Map-Eintrag.

Deshalb müssen wir nicht überprüfen, ob das Element existiert oder nicht - alles, was wir tun müssen, ist push_back auf dem remote Mitglied, da wir einen Iterator auf den neuen oder vorhandenen Eintrag zurück erhalten werden insert (Beachten Sie, dass die Karte selbst ihre Einträge als std::pair<key_type, value_type> speichert, also möchten wir, dass die second dieses Paares die SubscriptionInfo Instanz erhält).

Beachten Sie auch, dass wir keine separate Mitgliedsvariable benötigen, um die Anzahl der Server zu überwachen, da remote.size() die Anzahl der Einträge im Vektor zurückgibt. Wenn Sie externe Variablen wie no_of_servers verwenden, erhöht sich die Wahrscheinlichkeit, dass Fehler auftreten, da diese Variable nicht manuell aktualisiert wird, wenn Elemente dem Vektor hinzugefügt oder daraus entfernt werden. Verwenden Sie stattdessen immer std::vector::size(), um die richtige Menge zu erhalten.

einen Eintrag zu löschen, alles, was Sie brauchen, ist der key Wert, und der Eintrag durch den Aufruf der std::map::erase() Funktion gelöscht wird:

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

Edit: Wenn Sie einen Compiler verwenden, die nicht C++ 11-kompatibel ist

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

Danke für die ausführliche Erklärung!Jetzt verstehe ich, wie ich das mit Map und Vektor erreichen kann. –

+0

Jetzt verwende ich es wie folgt: 'für (i = 0; ich < sub_data-> no_of_svrs; i ++) { (* itr). Second.remote.push_back ({sub_data-> remote [i] .r_ip, sub_data-> remote [i] .r_port}); } ' Aber erhalten folgenden Fehler beim Kompilieren: Fehler: erwartete primäre Ausdruck vor '{' Token –

+0

Verwenden Sie einen Standard-C++ 11 Compiler? Die Syntax verwendet den Klammerinitialisierer, der bei den Compilern 03 und 1998 nicht vorhanden ist. – PaulMcKenzie

Verwandte Themen