Table of Contents
Motivation
Auf meiner Lernreise in die Welt der Robotik ist eines meiner Ziele, mein angestaubtes C++-Wissen aufzubessern.
Heute schauen wir uns das Konzept von std::array an.
Wie war es früher?
Vor C++11 musste man C-Style-Arrays benutzen:
TEST(ArrayTest, CStyleArray) {
int my_int_array[3] = {1, 2, 3};
EXPECT_EQ(my_int_array[0], 1);
EXPECT_EQ(my_int_array[1], 2);
EXPECT_EQ(my_int_array[2], 3);
}
Das hat natürlich ein paar Nachteile:
Sizeof kompliziert
Die Funktion sizeof() kann eigentlich nicht direkt für Arrays verwendet werden, da sie die Größe einer Datenstruktur in Bytes angibt.
Das können wir in folgendem Beispiel sehen. Ein Int-Array der Größe drei ist 12 Byte groß ein.
Ein Double-Array der Größe drei hat 24 Byte.
TEST(ArrayTest, CStyleArraySize) {
int my_int_array[3];
double my_double_array[3];
EXPECT_EQ(sizeof(my_int_array), 12);
EXPECT_EQ(sizeof(my_double_array), 24);
}
Deswegen musste man das Ergebnis von sizeof des Arrays noch mal durch die Größe des Datentyp teilen.
Decaying
Pointer Decay ist ein weiteres Problem von C-Style-Arrays.
In diesem Beispiel sehen wir, dass ein paar Zeiger an eine Funktion übergeben ist, Array nur noch durch den Zeiger repräsentiert wird.
Sizeof von diesem Datentyp ist normalerweise acht, weil es sich um einen 64 Bit Zeiger handelt.
int get_size(const int *arr)
{
return sizeof(arr);
}
TEST(ArrayTest, CStyleArrayPointerDecay) {
int my_int_array[3];
EXPECT_EQ(sizeof(my_int_array), 12);
EXPECT_EQ(get_size(my_int_array), 8); // decays to 64bit pointer
}
Unsicherer Indexzugriff
Auch der Zugriff auf die Daten wie Index Operator ist nicht ungefährlich, weil nicht überprüft wird, ob es sich um einen gültigen Index handelt.
D.h. es fliegt keine Exception sondern das Programm stürzt normalerweise ab.
Wenn man folgenden Code ausführt:
TEST(ArrayTest, CStyleArrayIndex) {
int my_int_array[3] = {1, 2, 3};
my_int_array[4] = 1;
EXPECT_EQ(my_int_array[4], 1);
}
Bekommt man:
Process finished with exit code 134 (interrupted by signal 6:SIGABRT)
std::array – modernes C++
Jetzt wollen wir uns mal anschauen, wie das std::array funktioniert.
Seit C++11 kann man den header <array>
dass dem C-Style-Array recht ähnlich sieht. Auch der Zugriff auf die Elemente mit dem Index Operator ist identisch:
TEST(ArrayTest, StdArray) {
std::array<int, 3> my_std_array = {1, 2, 3};
EXPECT_EQ(my_std_array[0], 1);
EXPECT_EQ(my_std_array[1], 2);
EXPECT_EQ(my_std_array[2], 3);
}
Was macht std::array besser?
size()-Funktion
std::array besitzt eine size()-Methode, die die korrekte Größe des Arrays ausgibt:
TEST(ArrayTest, StdArraySize) {
std::array<int, 3> my_int_array{};
std::array<int64_t, 3> my_int_64_array{};
EXPECT_EQ(my_int_array.size(), 3);
EXPECT_EQ(my_int_64_array.size(), 3);
}
at()-Funktion
Die at()-Methode greift wie der Index-Operator auf das n-te Element zu:
TEST(ArrayTest, StdArrayAt) {
std::array<int, 3> my_std_array = {1, 2, 3};
EXPECT_EQ(my_std_array.at(0), 1);
EXPECT_EQ(my_std_array.at(1), 2);
EXPECT_EQ(my_std_array.at(2), 3);
}
Auch das Setzen der Elemente geht über die at()-Methode:
TEST(ArrayTest, AddElementsToArrayWithAt) {
std::array<int, 3> my_array{};
my_array.at(0) = 1;
my_array.at(1) = 2;
my_array.at(2) = 3;
EXPECT_EQ(my_array[0], 1);
EXPECT_EQ(my_array[1], 2);
EXPECT_EQ(my_array[2], 3);
}
Gut ist, dass sie eine Exception wirft, wenn der Zugriff außerhalb des Arrays erfolgt:
Die Exception kann dann über ein try/catch zur Laufzeit gefangen werden.
TEST(ArrayTest, ArrayTestCatchException) {
std::array<int, 4> my_std_array = {8, 7, 6, 5};
try
{
std::cout << "Element at postion 4: " << my_std_array.at(4) << std::endl;
}
catch (const std::out_of_range& ex)
{
std::cerr << ex.what() << '\n';
EXPECT_NE(ex.what(), nullptr);
}
}
Arrays als Funktionsparameter
void power2(std::span arr)
{
for (int & i : arr) {
i *= 2;
}
}
TEST(ArrayTest, StdArrayFunctionCall) {
std::array<int, 4> my_std_array = {8, 7, 6, 5};
power2(my_std_array);
EXPECT_EQ(my_std_array[0], 16);
}
sort
Da sich ein std::array wie ein normaler STL-Container verhält, lässt sich das array mit std::sort sortieren:
TEST(ArrayTest, StdArraySort) {
std::array<int, 4> my_std_array = {8, 7, 6, 5};
std::sort(my_std_array.begin(), my_std_array.end());
EXPECT_EQ(my_std_array[0], 5);
}
TEST(ArrayTest, StdArraySortWithRanges) {
std::array<int, 4> my_std_array = {8, 7, 6, 5};
std::ranges::sort(my_std_array);
EXPECT_EQ(my_std_array[0], 5);
}
Beispiel aus der Robotik
Kompletter Code
https://github.com/jboegeholz/modern_cpp/blob/master/tests/02_test_std_array.cpp






