2013-03-30 17 views
5

Mam std::map<int, std::vector<SomeStruct>>, i dostarczam zapytanie takie jak: std::vector<SomeStruct> FindData(int key).Czy moja funkcja powinna zwrócić wskaźnik do std :: vector lub odwołanie do std :: vector?

Aby zapobiec kopiowaniu całych danych, zmieniam je na std::vector<SomeStruct>& FindData(int key).
Ale, nie będzie danych dla niektórych key, więc czasami nie mam nic do zwrócenia.
W takim przypadku deklaruję zmienną zakresu pliku, która jest pusta std::vector<SomeStruct> i zwraca ją.

Ale jeśli wybiorę wskaźnik do wektora, czyli std::vector<SomeStruct>* FindData(int key), mogę po prostu zwrócić NULL dla nieistniejącego key.

Który z nich jest lepszy?
dowiedziałem się, że wskaźnik do std::vector jest złe (lub dziwne? Nie jestem pewien) w pytaniu (Is there other syntax for this pointer operation?)
A ja osobiście jak odniesienie do std::vector też tak, że można używać operator[] łatwiejsze, ale wadą jest to muszę oświadczyć dodatkowa pusta zmienna dla niego.

przykład

Code to tak: W SomeClass.h

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

Teraz w SomeClass.cpp:

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

Przypadek 2:

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

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

    return &(It->second); 
} 

Patrz ence:
Zalety: wygląda jak normalny std::vector.
Minusy: zadeklarowano dodatkową zmienną.

Wskaźnik:
Plusy: Krótsza funkcja zapytania i nie potrzeba innej zmiennej.
Minusy: wygląda dziwnie (?!), a nie możesz zadzierać p[i], musisz (*p)[i], co jest denerwujące.

Który z nich jest lepszy?

+0

Powrót odniesienie; domyślny skonstruowany wektor jest lekkim obiektem, więc posiadanie tego dodatkowego 'EmptyVector' wokół nie powinno być powodem do niepokoju. Jeśli zwrócisz 'nullptr', cały kod klienta będzie musiał zawierać sprawdzanie tego, co osobiście uważam za bardziej irytujące niż sprawdzanie pustego wektora. – Praetorian

+0

@Praetorian: Mam podobną myśl, dlatego wolę referencje. Ale klient musi również sprawdzić 'if (p.empty()) return', więc może instrukcje typu null-check nadal istnieją :( –

Odpowiedz

0

Jeśli nie przeszkadza tworząc nowe wpisy dla klawiszy unfound następnie można użyć tego kodu:

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

Alternatywnym podejściem, że unika nowe wpisy dla klawiszy unfound:

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: Nie chcę wprowadzać dodatkowego wpisu na nieistniejącym kluczu, dziękuję! –

+0

@MarsonMao OK, opublikowałem alternatywne rozwiązanie – StackedCrooked

+0

Zastanów się 'FindDatas (non_existing_key) .push_back (blah)'. (Ten sam problem istnieje w oryginalnym kodzie, chociaż) –

1

Można Podaj także wartość wyjściową jako parametr, aby można było dodać wynik modułu wyliczającego lub wyniku bool jako wynik metody:

namespace 
    { 
     DataVec EmptyVector; 
    } 

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

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

     output = It->second; 
        return true; 
    } 
1

To zależy od wymagań projektowych. Jeśli wywołanie tej funkcji z indeksem, który nie zawiera odpowiedniego elementu, jest błędem programowania, to kod powinien zostać przerwany. Jeśli jest to błąd użytkownika, powinien wyrzucić wyjątek. Jeśli jest to część oczekiwanego użycia, masz trzy alternatywy, znowu w zależności od twojego projektu.Możesz zgłosić problem, zwykle przez zwrócenie wskaźnika pustego lub zwrócenie wartości typu Boolean z funkcji, która pobiera odniesienie dla wyniku. Możesz cicho zwrócić nowo utworzony prawidłowy obiekt, tak jak robi to std::set. Możesz zwrócić obiekt wartownika, który nie jest częścią twojego kontenera, a użytkownicy będą musieli sprawdzić, czy to jest to, co otrzymali, zanim użyją zwróconej wartości.