Często w programach napisanych w C do pobierania rozmiaru tablic alokowanych przez kompilator na stosie stosuje się prostą konstrukcję z operatorem sizeof
, opakowana w makro:
#define SizeOfArray(array) sizeof(array) / sizeof(array[0]) |
W C++ zamiast makra lepiej wykorzystać wzorzec, a wtedy można to przedstawić tak:
template<typename T, size_t N> inline size_t SizeOfArray(const T (&)[N]) { return N; } |
Wersja cpplusowa jest bezpieczniejsza, próba wywołania SizeOfArray()
na wskaźniku zakończy się bledem w czasie kompilacji, w przeciwieństwie do makra, które dopiero da znać w run-timie.
To tyle słowami wstępu. Zresztą nie chciałem zbytnio o tym pisać, jedynie wspomnieć o prostej możliwości używania algorytmów z STL-a na zwykłych tablicach. Większość algorytmów działa poprawnie na wskaźnikach zamiast iteratorów.
int array[] = { 1, 2, 3, 4, 5 }; std::copy(array, array + SizeOfArray(array), std::ostream_iterator<int>(std::cout, " ")); |
Dla nieco lepszego i czytelniejszego kodu, można dopisać 2 szablonowe funkcje służące do pobierania "iteratorów" dla tablicy, bez konieczności pamiętania o dodawaniu rozmiaru przy wskaźniku "na koniec".
template<typename T, size_t N> inline T* begin(T (&array)[N]) { return array; } template<typename T, size_t N> inline T* end(T (&array)[N]) { return array + N; } |
Teraz wystarczy:
std::copy(begin(array), end(array), std::ostream_iterator<int>(std::cout, " ")); |
Idąc dalej można specjalizować powyższe funkcje również dla zwykłych iteratorów, wtedy będzie można używać funkcji begin()
i end()
w jednakowy sposób dla zwykłych tablic i kontenerów z biblioteki STL.
Napsianie tego zostawiam czytelnikom (jeśli jacys są ;p)jako zadanie domowe ;)
Na jakimś forum przypadkiem trafiłem właśnie na takie specjalizacje, ponoć w starej (?) implementacji array w boost było to używane, ale nie mogę tego potwierdzić.
Problem z wersja SizeOfArray jest taki, ze nie resolve’uje sie ona w czasie kompilacji. Wersje bez tej wady przedstawilem swego czasu tutaj: http://msinilo.pl/blog/?p=64
(BTW, nazwa tez nie najszczesliwsza, bo SizeOfArray to po prostu sizeof(array)).
Dziwne, bo przeciez operator sizeof jak i wzorce są rozwijane w czasie kompilacji.
Zrobilem testy i dla tablicy z 5 intami, VC9 i GCC3.4.x dla obu wersji wygenerowal podobny kod z liczba 5, bez zadnych dodatkowych operacji jakie musialyby byc wykonane w czasie dzialania.
No tak, Count bylby lepszy ;p
Odwiedzam co jakis czas Twoja strone, tam chyba kiedys widzialem to rozwiazanie ;)
Operacji dodatkowych nie ma, ale takie cos nie przejdzie:
int array2[SizeOfArray(array)];
Po prostu kompilator nie jest w stanie okreslic rezultatu (teoretycznie moglby, ale w C++ tego nie zrobi).
Szkoda, jak dobrze pamietam, C++0x cos zmienia w tej kwestii przez wprowadzenie constexpr.