2009-07-22 7 views
2

Ich würde sagen, ich bin kein Experte für die Verwendung der STL. Hier ist mein Problem, ich habe eine Klasse namens LdapClientManager, die eine Anzahl von LDAP-Clients verwaltet, die von ID verwaltet werden. Der Behälter der LdapClients hält, wird als Mitglied Variable deklariert dh"Klasse Std :: Karte ohne Vorlage Parameter verwendet" Fehler

typedef std::map<int, LdapClient *> LdapClientMap; 
LdapClientMap _ldapClientMap; 

Die folgende Funktion mit dem Fehler kompilieren fehlschlägt:

LdapClient * LdapClientManager::getLdapClient(unsigned int templateID) 
{ 
    // Do we have an LdapClient 
    LdapClientMap::const_iterator it = _ldapClientMap.find(templateID); 
    if (it == std::map::end) { 
     // no existing client, lets create it 
     LdapClient * ldapClient = new LdapClient(); 
     if (ldapClient == NULL) { 
      // TODO: handle out of memory condition 
     } 

     _ldapClientMap[templateID] = ldapClient; 
     return ldapClient; 
    } 

    return it->second; 
} 

Leider bekomme ich folgende Fehlermeldung bei der Kompilierung, was bedeutet es . Ich habe noch keine Lösung in Google gefunden.

LdapClientManager.cc: In Memberfunktion LdapClient* LdapClientManager::getLdapClient(unsigned int)': LdapClientManager.cc:33: Template-Klasse std :: map‘ohne Vorlage verwendeten Parameter

+1

Nur eine Anmerkung, neue gibt NULL nicht aus Speicherbedingungen zurück (es sei denn, Sie verwenden alte Compiler wie VC6). Es löst std :: bad_alloc aus. – Naveen

Antwort

11

std::map::end ersetzen _ldapClientMap.end() mit. Außerdem gibt new nie 0 zurück, es wird eine Ausnahme ausgelöst, wenn die Zuweisung fehlschlägt.

Beachten Sie, dass das Programm viel kürzer gemacht werden kann.

LdapClient * LdapClientManager::getLdapClient(unsigned int templateID) 
{ 
    LdapClient *& value = _ldapClientMap[templateID]; 
    if (value == 0) 
     value = new LdapClient(); 
    return value; 
} 
+0

Typenname vor LdapClientMap? Warum?! – EFraim

+0

Whoops, entfernt. Es wäre notwendig, wenn "getLdapClient" eine Vorlage wäre. Danke, Efraim. – avakar

+1

In std :: map ist operator [] eine Mutationsoperation. Dies kann die Verwendung einschränken (kann nicht innerhalb einer konstanten Methode verwendet werden) oder kann das System beeinflussen (ein späterer Aufruf von find() führt zu einem Iterator im Array, die Karte wird für jeden fehlgeschlagenen Test im Speicher vergrößert ...) –

3

Es bedeutet genau das, was es bedeutet. std::map ist eine Klassenvorlage. Es ist keine Klasse an und für sich. Es benötigt Template-Parameter, die Sie bei der Definition des Typs verwendet haben. Später sagen Sie std::map::end, und der Compiler sagt, dass auch Parameter benötigt werden.

Aber Sie wahrscheinlich _ldapClientMap.end() gemeint. Jede Karte hat ihr eigenes Ende; end ist keine statische Funktion, daher müssen Sie sie für eine Instanz aufrufen. Wenn statisch wäre, müssten Sie Vorlagenparameter bereitstellen, genau wie bei der Definition des Typs: std::map<int, LdapClient*>::end.

1

std :: map :: end() ist eine Member-Funktion der Container-Instanz und kein universeller Wert, daher müssen Sie das Ergebnis von std :: map :: find() gegen _ldapClientMap.end überprüfen().

Noch ein paar Vorschläge, den Code zu verbessern:

  • Standard C++ Container haben Wert Semantik (sie wollen das eigentliche Objekt speichern und nicht ein Zeiger auf das Objekt). Wenn Sie wirklich Zeiger auf LdapClients anstelle der LdapClient Objekte selbst speichern müssen, würde ich dringend empfehlen, sie in einem geeigneten Smart Pointer wie boost :: shared_ptr (nicht std :: auto_ptr, das nicht funktioniert) zu wickeln. Auf diese Weise funktioniert die automatische Speicherverwaltung der std :: map weiterhin und zerstört die Objekte wie vorgesehen. Wenn Sie keinen intelligenten Zeiger verwenden oder das tatsächliche LdapClient-Objekt in den Container einfügen möchten, müssen Sie die Lebensdauer der Objekte manuell verwalten und ggf. löschen, um Speicherverluste zu vermeiden. Meine Präferenz wäre, den Typ der Karte in std :: map zu ändern, es sei denn, die LdapClient-Objekte sind polymorph.
  • Wenn Sie nicht einen sehr veralteten Compiler verwenden, wird die Überprüfung des Ergebnisses von regulär new() gegen 0 oder NULL keine neuen Erkenntnisse liefern, da new in diesen Tagen ein std :: bad_alloc wirft, wenn er keinen Speicher zuweisen kann welcher Grund auch immer.
  • Anstelle von _ldapClientMap [x] = y; Um ein neues Element einzufügen, würde ich _ldapClientMap verwenden.insert (LdapClientMap :: value_type (x, y)), da letzterer keinen vorhandenen Wert für den Schlüssel x überschreibt (was ersteres tun würde) und 'false' zurückgibt, falls der Schlüssel bereits in der Map existiert. Das ist natürlich, wenn das Ihre Absicht ist.
+0

Danke für die Hinweise, da waren einige gute Kommentare drin. – Matt

-1
LdapClientMap _ldapClientMap; 

Sie sollten mit Namen, die mit einem Unterstrich vermeiden. Technisch gesehen ist es ein undefiniertes Verhalten, auch wenn der Compiler dies erlaubt, weil Sie dadurch Konflikte mit aktuellen oder zukünftigen reservierten Namen haben.

+0

Es ist nicht. Ein einzelner führender Unterstrich vor Kleinbuchstaben ist nur im globalen Gültigkeitsbereich reserviert. Klassenmitglieder und lokale Variablen sind in Ordnung, und er deklariert eine Mitgliedsvariable. Ein einzelner führender Unterstrich vor einem Großbuchstaben und ein doppelter Unterstrich irgendwo in Bezeichner sind in allen Gültigkeitsbereichen reserviert (daher verwenden alle STL-Implementierungen '_Foo' für Argument- und Elementnamen). Standard besagt explizit, dass Benutzercode solche Bezeichner über Makros neu definiert). –

+0

Ich verwende immer einen einzelnen Unterstrich für Mitgliedsvariablen, um sie zu unterscheiden. – Matt

Verwandte Themen