std::array - Keine dynamische Speicherallokation notwendig

std::array verbindet das Beste aus zwei Welten. Zum einen besitzt es die Größe und Effizienz eines C-Arrays, zum anderen bietet es das Interface eines std::vector an.

 

std::array besitzt ein Alleinstellungsmerkmal unter den sequentiellen Containern der Standard Template Library. Seine Größe lässt sich nicht dynamisch anpassen. Für seine Initialisierung gelten besondere Regeln.

Die Initialisierung

Bei der Initialisierung eines std::array gelten die Regeln der Aggregat Initialisierung:

  • std::array<int,10> arr: Die 10 Elemente werden nicht initialisiert.
  • std::array<int,10>arr{}. Die 10 Elemente werden auf ihren Default initialisiert.
  • std::array<int,10>arr{1,2,3,4): Die restlichen Elemente werden auf ihren Default initialisiert.

 Als sequentieller Datentyp unterstützt er den Indexzugriff.

Indexzugriff

std::array arr unterstützt den Indexzugriff in drei Formen:

  • arr[n]:Zugriff auf das n-te Element ohne Überprüfung der Array-Grenzen.
  • arr.at(n):Zugriff auf das n-te Element mit Überprüfung der Array-Grenzen. Gegebenenfalls wird eine std::range_error-Ausnahme geworfen.
  • std::get<n>(arr):Zugriff auf das n-te Element mit der Syntax des std::tuple

std::get<n>(arr) unterstreicht die Verwandtschaft vom std::array mit dem std::tuple. Während std::array ein homogener Container fester Länge ist, ist std::tuple ein heterogener Container fester Länge.

Ich habe behauptet, dass C++-Array ist so speichereffizient wie das C+-Array. Den Beweis bin ich aber schuldig geblieben.

Speichereffizienz

In meinem kleinen Programm stelle ich die Speichereffizienz eines C-Arrays, eines C++-Arrays und eines std::vector gegenüber.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// sizeof.cpp

#include <iostream>
#include <array>
#include <vector>
 
 
int main(){
  
  std::cout << std::endl;
  
  std::cout << "sizeof(int)= " << sizeof(int) << std::endl;
  
  std::cout << std::endl;
  
  int cArr[10]= {1,2,3,4,5,6,7,8,9,10};
  
  std::array<int,10> cppArr={1,2,3,4,5,6,7,8,9,10};
  
  std::vector<int> cppVec={1,2,3,4,5,6,7,8,9,10};
  
  std::cout << "sizeof(cArr)= " << sizeof(cArr) << std::endl;  
  
  std::cout << "sizeof(cppArr)= " << sizeof(cppArr) << std::endl;
  
  std::cout << "sizeof(cppVec) = "   << sizeof(cppVec) + sizeof(int)*cppVec.capacity() << std::endl;
  std::cout << "               = sizeof(cppVec): " << sizeof(cppVec) << std::endl;
  std::cout << "               + sizeof(int)* cppVec.capacity(): "   << sizeof(int)* cppVec.capacity() << std::endl;

  std::cout << std::endl;
  
}

 

Die Zahlen sprechen eine eindeutige Sprache.

sizeof

Sowohl das C-Array (Zele 22) als auch das C++-Array (Zeile 24) benötigen 40 Byte. Das entspricht der Größe sizeof(int)*10. Im Gegensatz dazu benötigt der std::vector 24 zusätzliche Bytes (Zeile 27) um seine Daten auf dem freien Speicher zu verwalten. cppVec.capacity() ist die Anzahl der Elemente, die der std::vector cppVec besitzen kann, ohne dass er neuen Speicher anfordern muss. Die Details zum Speichermanagement von std::vector und std::string habe ich in dem Artikel Automatisches Speichermanagement mit Containern detailiiert vorgestellt.

Um das Bild abzurunden, noch eine kleine Anwendung mit std::array.

std::array im Einsatz

Der wahre Mehrwert von std::array gegenüber dem C-Array ist es, dass sich die Algorithmen der Standard Template Library auf dem  std::array anwenden lassen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// array.cpp

#include <algorithm>
#include <array>
#include <iostream>

int main(){

  std::cout << std::endl;

  // output the array
  std::array <int,8> array1{1,2,3,4,5,6,7,8};
  std::for_each( array1.begin(),array1.end(),[](int v){std::cout << v << " ";});

  std::cout << std::endl;

  // calculate the sum of the array by using a global variable
  int sum = 0;
  std::for_each(array1.begin(), array1.end(),[&sum](int v) { sum += v; });
  std::cout << "sum of array{1,2,3,4,5,6,7,8}: " << sum << std::endl;

  // change each array element to the second power
  std::for_each(array1.begin(), array1.end(),[](int& v) { v=v*v; });
  std::for_each( array1.begin(),array1.end(),[](int v){std::cout << v << " ";});
  std::cout << std::endl;

  std::cout << std::endl;

}

 

So lässt sich array1 in Zeile 13 mit der Lambda-Funktion und dem for_each-Algorithmus ausgeben. Im Gegensatz dazu bindet die Lambda-Funktion die Summationsvariable sum in Zeile 19. Mit ihrer Hilfe werden die Elemente des std:.array zusammen addiert. Die Lambda-Funktion in Zeile 23 nimmt ihr Argument als Referenz an und kann daher jedes Element des std::array auf sein Quadrat abbilden. Alles nichts Besonderes, wäre der zugrundeliegende Container kein std::array.

Zum Abschluss noch die Ausgabe des Programms.

array

Wie geht's weiter?

Dieser Artikel war kurz und schmerzlos. Im nächsten Artikel schaue ich mir eines der prominentesten Feature von C++11 an, die Move-Semantik.

 

 

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Hole dir dein E-Book. Unterstütze meinen Blog.

 

 

Mentoring

Stay Informed about my Mentoring

 

Rezensionen

Tutorial

Besucher

Heute 3149

Gestern 2405

Woche 11355

Monat 38672

Insgesamt 3891386

Aktuell sind 35 Gäste und keine Mitglieder online

Kubik-Rubik Joomla! Extensions

Abonniere den Newsletter (+ pdf Päckchen)

Beiträge-Archiv

Sourcecode

Neuste Kommentare