2015-01-26 14 views
5

Załóżmy, że mam klasę "Widget". W mojej aplikacji tworzę dużo widżetów, które (dla lokalizacji pamięci podręcznej i innych powodów) trzymam w wektorze.Typ danych dla tabeli/indeksu odnośników do tablicy

Dla skutecznych wyszukiwań chciałbym wdrożyć bazę danych indeksu. Dla samego pytania załóżmy, że jest to prosta tablica przeglądowa od wskaźników int do elementów Widget we wspomnianym wektorze. Moje pytanie brzmi: Jaka powinna być zawartość tabeli odnośników. Innymi słowy, z jakiego typu należy wymienić znak zapytania w

using LookupTable = std::vector<?> 

widzę następujące opcje:

  • Referencje (Widget &, czy raczej, jak to ma być przypisane: reference_wrapper <widget>)
  • Wskaźniki (widget *)
  • Indeksy w wektorze widżet (size_t)
  • obiekty iterator wskazujący do wektora Widget (std :: vector <Widget> :: iterator)

Wśród tych opcji, wskaźniki wydają się być jedyną opcją, która nie dostać podważa zmiany rozmiaru wektorowych. Możliwe, że będę w stanie uniknąć zmiany rozmiaru, jednak implementacja tablicy odnośników będzie oznaczać przyjęcie założeń dotyczących implementacji wektorowej, która wydaje się nierozsądna z punktu widzenia "oddzielenia projektu".

Wskaźniki OTOH nie są zabezpieczone przed niebezpieczeństwem: jeśli rzecz, którą wydostaję z tabeli odnośników, była referencją, mogłem jej użyć tylko do uzyskania dostępu do odpowiedniego widżetu. Użycie wartości size_t mogę zrobić operacje bezsensowne jak mnożąc wynik przez 3. Weź również pod uwagę następujące dwa podpisy:

void doSomethingWithLookupResult(Widget& lookupResult); 
void doSomethingWithLookupResult(size_t lookupResult); 

ta pierwsza jest znacznie bardziej opisowe.

Podsumowując: Jakiego rodzaju danych można użyć do mojej tabeli odnośników, aby uzyskać zarówno oddzielenie od implementacji wektorowej, jak i bezpieczeństwo typu?

+0

Czy możesz podać przykład * sposobu * używania tabeli LookupTable? – Barry

+0

@ Barry: Tabela std :: vector jest uproszczeniem. Niemniej jednak powiedz, że widget ma wartość priorytetu. Następnie w tabeli wyszukiwania chcę szybko znaleźć pierwszy widżet z pierwotnej listy o podanym priorytecie. Byłoby to dosłownie odnośnikiem do wektora: widgetByPriority [priority]. Potem oczywiście chcę pracować z widżetem, który znalazłem, np. obliczyć jego rozmiar. – DanielM

Odpowiedz

1

Można utworzyć klasę reprezentującą indeks, który również przenosi informacje o typie (podczas kompilacji).

#include <vector> 

template <class T> 
struct typed_index { 
    typed_index(int i) : i(i) {} 

    template <class CONTAINER> 
    T &operator[](CONTAINER &c) { return c[i]; } 
    template <class CONTAINER> 
    const T &operator[](const CONTAINER &c) { return c[i]; } 

    int i; 
}; 

int main() { 
    std::vector<int> v1 = {0}; 
    std::vector<const char *> v2 = {"asd"}; 
    typed_index<int> i = 3; 
    int z = i[v1]; 
    const char *s = i[v2]; // will fail 
} 
+0

Stworzyło mi to głowę, dopóki nie pomyślałem, że 'operator []' został odwrócony ... indeks jest * na zewnątrz * nawiasy kwadratowe i pojemnik * wewnątrz * je! –

+0

Technicznie C zezwala na tę składnię dla tablic (nie będzie ona działać dla wektorów) – tohava

+0

Wiem, ale tylko dla * starych tablic stylów * 'spowodować 'arr [1]' jest równe '* (arr + 1)' tak ' 1 [arr] 'jest równe' * (1 + arr) 'ale i tak generuje mi ból głowy> _ < –

2

Użyj std :: wektor :: size_type (not size_t). std :: vector :: size_type może być size_t w większości implementacji, ale dla przenośności i przyszłościowej sake, zrobimy to dobrze.

Śmiało i wykonaj typedef: przy użyciu WidgetIndex = std :: vector :: size_type;

tak, że wygląda to uzasadnione:

void doSomethingWithLookupResult (WidgetIndex lookupResult);

Pozwala to uniknąć problemu z rozmiarem wektorów, który, podczas gdy użytkownik nie odtwarza go w pytaniu, ostatecznie wróci, aby cię ugryźć.

Nie graj z niektórymi typami zdefiniowanymi przez użytkownika, takimi jak tohava (bardzo sprytnie), proponuje się, chyba że masz zamiar używać tego idiomu dużo w swojej bazie kodu.Oto dlaczego nie:

  • Problemem, który jest rozwiązywany (typu bezpieczeństwa) jest prawdziwe i chcielibyśmy rozwiązanie z nim, jeśli jest „wolny”, ale w porównaniu do innych możliwości programistów C++ trzeba strzelać się w stopach, to nie jest tak duży problem.
  • Będziesz marnować czas. Twój czas na zaprojektowanie klasy, a następnie czasu każdego użytkownika bazy kodu (włączając w to siebie po tym, jak zapomniałeś wdrożenia w ciągu kilku miesięcy), który będzie patrzył na ten kod i będzie musiał go rozwiązać.
  • W pewnym momencie w przyszłości potkniecie się o tę "interesującą" narożną sprawę, której nikt z nas nie widzi teraz, patrząc na ten kod.

Wszystko, co powiedział, jeśli masz zamiar używać tego idiomu często w swojej bazie kodu (trzeba wiele klas, które są przechowywane w wektorach bardzo statyczne lub tablic), to może mieć sens, aby ta inwestycja. W takim przypadku obciążenie konserwacyjne jest rozłożone na więcej kodów, a możliwość użycia niewłaściwego typu indeksu z niewłaściwym pojemnikiem jest większa.

+0

Przyjmę odpowiedź tohavy, ponieważ zapewnia ona konkretną odpowiedź, która odpowiada wymaganiom sformułowanym w pierwotnym pytaniu. Jednak widzę twój punkt widzenia i będę pamiętać o twoich radach. – DanielM