5.6 Tablice typu std::array

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 ):


P28: Arrays.cpp     Tablice typu std::array

      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 ) 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 2019; 23:59