2013-03-30 10 views
5

Ich habe eine std::map<int, std::vector<SomeStruct>>,
und bieten eine Abfrage wie std::vector<SomeStruct> FindData(int key).Sollte meine Funktion einen Zeiger auf std :: vector oder einen Verweis auf std :: vector zurückgeben?

Um zu verhindern, dass die gesamten Daten kopiert werden, ändere ich sie auf std::vector<SomeStruct>& FindData(int key).
Aber es wird keine Daten für bestimmte key geben, so dass ich manchmal nichts zurückgeben kann.
In diesem Fall deklariere ich eine Dateibereichsvariable, die eine leere std::vector<SomeStruct> ist, und gebe sie zurück.

Aber wenn ich den Zeiger auf Vektor, das ist std::vector<SomeStruct>* FindData(int key), dann kann ich einfach NULL für nicht vorhandene key zurückgeben.

Welcher ist besser?
erfuhr ich, dass Zeiger auf std::vector schlecht ist (oder seltsam? Nicht sicher) in der Frage (Is there other syntax for this pointer operation?)
Und ich persönlich mag Bezug auf std::vector zu, so dass ich operator[] einfacher verwenden kann, aber der Nachteil ist, ich habe zu erklären, eine zusätzliche leere Variable dafür.

Codebeispiel sind wie: In SomeClass.h

typedef std::vector<SomeStruct> DataVec; 
typedef std::map<int, DataVec> DataMap; 
DataMap m_DataMap; 

jetzt in SomeClass.cpp:

Fall 1:

namespace 
{ 
    DataVec EmptyVector; 
} 

DataVec& FindDatas(int key) 
{ 
    DataMap::iterator It = m_DataMap.find(key); 

    if (It == m_DataMap.end()) return EmptyVec; 

    return It->second; 
} 

Fall 2:

DataVec* FindDatas(int key) 
{ 
    DataMap::iterator It = m_DataMap.find(key); 

    if (It == m_DataMap.end()) return NULL; 

    return &(It->second); 
} 

Siehe ence:
Pros: sieht wie normal aus std::vector.
Nachteile: Zusätzliche Variable deklariert.

Zeiger:
Vorteile: Kürzere Abfragefunktion und keine andere Variable.
Nachteile: sieht komisch aus (?!), und Sie können nicht p[i] Jause, müssen Sie (*p)[i], was ärgerlich ist.

Welcher ist besser?

+0

Eine Referenz zurückgeben; Ein standardmäßig konstruierter Vektor ist ein leichtgewichtiges Objekt, daher sollte der zusätzliche 'EmptyVector' keinen Anlass zur Sorge geben. Wenn Sie 'nullptr 'zurückgeben, muss der gesamte Client-Code eine Überprüfung enthalten, was für mich persönlich ärgerlicher ist, als nach einem leeren Vektor zu suchen. – Praetorian

+0

@Praetorian: Ich habe ähnliche Gedanken, deshalb bevorzuge ich Referenz. Aber der Client muss auch nach 'if (p.empty()) return' suchen, so dass die Null-Check-ähnlichen Anweisungen immer noch existieren :( –

Antwort

0

Wenn Sie nichts dagegen keine neuen Einträge für nicht gefundene Schlüssel zu schaffen, dann können Sie diesen Code verwenden:

DataVec& FindDatas(int key) 
{ 
    return m_DataMap[key]; 
} 

Ein alternativer Ansatz, der für nicht gefundene Schlüssel neue Einträge vermeidet:

DataVec& FindDatas(int key) 
{ 
    DataMap::iterator It = m_DataMap.find(key);  
    if (It == m_DataMap.end()) { 
     // created on first unfound key and stays 
     // alive until the end of the program 
     static DataVec fEmpty; 
     return fEmpty; 
    }  
    return It->second; 
} 
+0

Hi: Ich möchte keinen extra Eintrag für einen nicht existierenden Schlüssel einführen, danke! –

+0

@MarsonMao Ok, ich postete eine alternative Lösung – StackedCrooked

+0

Betrachte 'FindDatas (non_existing_key) .push_back (blah)'. (Das gleiche Problem existiert jedoch im Originalcode) –

1

Sie können geben Sie auch die Referenz der Ausgabe als Parameter an, so dass Sie ein Enumerator- oder Boolergebnis als Methodenausgabe hinzufügen können:

1

Es hängt von Ihren Designanforderungen ab. Wenn ein Aufruf dieser Funktion mit einem Index, der kein entsprechendes Element enthält, ein Programmierfehler ist, sollte der Code abgebrochen werden. Wenn es sich um einen Benutzerfehler handelt, sollte eine Ausnahme ausgelöst werden. Wenn es Teil der erwarteten Verwendung ist, haben Sie drei Alternativen, wiederum abhängig von Ihrem Design.Sie können das Problem kennzeichnen, indem Sie normalerweise einen Nullzeiger zurückgeben oder einen booleschen Wert von einer Funktion zurückgeben, die eine Referenz für das Ergebnis verwendet. Sie können ein neu erstelltes gültiges Objekt ruhig zurückgeben, wie es std::set tut. Sie können ein Sentinel-Objekt zurückgeben, das nicht Teil Ihres Containers ist, und die Benutzer müssen prüfen, ob sie das erhalten haben, bevor sie den zurückgegebenen Wert verwenden.