Algorytmy STL na tablicach
• tech • 292 słowa • 2 minuty czytania
Często w programach napisanych w C do pobierania rozmiaru tablic (ilości elementów) alokowanych przez kompilator na stosie stosuje się prostą konstrukcję z operatorem sizeof
. ładnie “opakowaną” w makro do łatwego użycia:
#define SizeOfArray(array) sizeof(array) / sizeof(array[0])
W C++ zamiast makra lepiej wykorzystać wzorzec, a wtedy można to przedstawić w takiej postaci:
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ę błędem w czasie kompilacji, w przeciwieństwie do makra, które dopiero da znać o tym problemie w run-time.
To tyle słowami wstępu, bo nie chciałem zbytnio o tym teraz pisać.
Głównym tematem miała być wzmianka o prostej możliwości używania algorytmów pochodzącym z biblioteki STL na zwykłych tablicach. Większość algorytmów działa poprawnie na wskaźnikach, tak jak gdyby były iteratorami.
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 “surowej” tablicy, załatwiając tym konieczność 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 kod wykorzystujący algorytm std::copy
na tablicy wygląda znacznie lepiej:
int array[] = { 1, 2, 3, 4, 5 };
std::copy(begin(array), end(array), std::ostream_iterator<int>(std::cout, " "));
Idąc dalej można byłoby 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.
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ć. Napisanie tego zostawiam czytelnikom jako zadanie domowe ;)
Komentarze (4)
Problem z wersja SizeOfArray jest taki, ze nie resolve’uje sie ona w czasie kompilacji. Wersje bez tej wady przedstawilem swego czasu tutaj: msinilo.pl/blog/?p=64
(BTW, nazwa tez nie najszczesliwsza, bo SizeOfArray to po prostu sizeof(array)).
Dziwne, bo przecież operator
sizeof
jak i wzorce są rozwijane w czasie kompilacji. Zrobiłem nawet testy i dla tablicy z 5 intami, VC9 i GCC3.4.x dla obu wersji wygenerował podobny kod z liczbą 5, bez żadnych dodatkowych operacji jakie musiałyby być wykonane w czasie działania.No tak, “Count” w nazwie byłby tutaj lepszy.
Odwiedzam co jakiś czas Twoją stronę, tam chyba kiedyś widziałem to rozwiązanie ;)
Operacji dodatkowych nie ma, ale takie cos nie przejdzie:
Po prostu kompilator nie jest w stanie okreslic rezultatu (teoretycznie moglby, ale w C++ tego nie zrobi).
Szkoda, jak dobrze pamiętam, C++0x coś zmienia w tej kwestii przez wprowadzenie constexpr.