Od wersji standardu C++11 istnieje w bibliotece standardowej specjalny typ danych std::array (z nagłówka array). Właściwie, jak się przekonamy, jest to tzw. szablon klasy. Na razie wystarczy nam wiedzieć, że zamiast tworzyć „normalne” tablice w stylu C, możemy tworzyć obiekty klasy array<Typ,size>, gdzie Typ jest typem elementów tablicy, a size jest jej wymiarem. W dalszym ciągu podany wymiar musi być stałą kompilacji. Zmiennej tego typu można używać tak jak tablicy, poprzez indeksowanie. Również inicjowanie wygląda podobnie jak dla zwykłych tablic; na przykład
1. #include <iostream>
2. #include <array>
3. int main() {
4. std::array<double,5> a1;
5. std::array<int,3> a2{1,2,3};
6. for (int i = 0; i < 5; ++i) a1[i] = i+0.5;
7. for (int i = 0; i < 5; ++i) std::cout << a1[i] << " ";
8. std::cout << std::endl;
9. for (int i = 0; i < 3; ++i) std::cout << a2[i] << " ";
10. std::cout << std::endl;
11. }
drukuje
0.5 1.5 2.5 3.5 4.5
1 2 3
Tablice tego typu mają jednak szereg zalet w stosunku do zwykłych tablic.
Przede wszystkim są obiektami i „znają” swój wymiar, również wtedy,
kiedy zostaną wysłane do funkcji jako argument. Można ten wymiar
uzyskać poprzez wywołanie metody na rzecz takiego obiektu:
arr.size() (linia ➊ w przykładzie poniżej),
albo poprzez wywołanie bibliotecznej funkcji:
std::size(arr) (linia ➌),
gdzie
arr
jest taką tablicą. Jak widzimy w przykładzie,
to będzie działać również dla tablicy przesłanej do funkcji
(w tym przypadku funkcji
printArray).
Do poszczególnych elementów można się odwoływać poprzez
indeks, jak to już widzieliśmy, albo poprzez metodę:
arr.at() (linia ➍):
1. #include <array>
2. #include <cstddef> // size t
3. #include <iostream>
4. #include <string>
5. using std::array; using std::cout;
6.
7. void printArray(const array<int,8>& a) {
8. cout << "Version <int,EIGHT>: "
9. << "a.size() = " << a.size() << "\n"; ➊
10. for (const auto& e : a) cout << e << " "; ➋
11. cout << "\n";
12. }
13.
14. template <typename E, std::size_t SIZE>
15. void printArray(const array<E,SIZE>& a) {
16. cout << "Template version: "
17. << "std::size(a) = " << std::size(a) << "\n"; ➌
18. for (std::size_t i = 0; i < a.size(); ++i)
19. cout << a.at(i) << " "; ➍
20. cout << "\n";
21. }
22.
23. int main() {
24. array<int,8> ai{1,2,3,4,5};
25. for (auto& e : ai) ++e; ➎
26. printArray(ai);
27.
28. array<std::string,5> as{"K","L","M","D"};
29. for (auto& e : as) e += "!";
30. printArray(as);
31. }
Przykład ilustruje też kilka elementów, których jeszcze nie znamy. Forma pętli (na przykład w liniach ➋ i ➎) jest charakterystyczna dla kolekcji z biblioteki standardowej — omówimy ją w rozdziale o pętlach . Z kolei druga forma funkcji printArray jest tak naprawdę szablonem — dzięki temu może działać dla tablic o różnych typach elementów i o różnych rozmiarach. Więcej o tym w rozdziale o szablonach .
Program drukuje
Version <int,EIGHT>: a.size() = 8
2 3 4 5 6 1 1 1
Template version: std::size(a) = 5
K! L! M! D! !
Może się zdarzyć, że tablicę typu
std::array
chcemy
wysłać do funkcji, która oczekuje zwykłej tablicy (czyli
właściwie wskaźnika). Można to łatwo zrobić poprzez wywołanie
arr.data(), które zwraca te same dane
jako wskaźnik do „zwykłej” C-tablicy.
T.R. Werner, 23 lutego 2022; 19:40