Sökresultat för

Använder du STL array på rätt sätt

5 minuter i lästid
Jens Riboe
Jens Riboe
Senior/Expert Software Developer
Använder du STL array på rätt sätt

I min förra artikel beskrev jag ingående användning av std::vector. I denna artikel, tar jag upp vad du behöver veta om dess lillebror std::array. Den avgörande skillnaden mellan dessa två är std::vector består av ett heap-allokerat minnesblock som omallokeras i takt med att fler element sätts in, medan std::array saknar rörliga delar utan består av ett statiskt minnesblock där objektet är placerat, vanligtvis på stack:en.

Du skapar ett std::array objekt med två template parametrar, den första är element-typen, precis som för std::vector, och den andra är vilken storlek eller kapacitet den ska ha.

#include <array>
//...
auto a = std::array<int, 6>{1,2,3};
std::println("{} ({}, {})", a, a.size(), a.empty());
//prints: [1, 2, 3, 0, 0, 0] (6, false)

Här har jag skapat en med plats för 6 element, initierat de 3 första och låtit default-initiera de övriga. Eftersom storleken är fixerad, så har man föga nytta av metoderna size() respektive empty(). Enda gången den sistnämnda returnerar true, är när man skapat en array med storlek 0; men vad ska man med en sådan till?

auto a = std::array<int, 1>{};
std::println("a: {} ({})", a, a.empty());  //prints: a: [0] (false)
auto b = std::array<int, 0>{};        
std::println("b: {} ({})", b, b.empty());  //prints: b: [] (true)

Om du inte vill initiera array:en, kan du populera den via t.ex. en for-loop.

auto a = std::array<int, 5>{};
std::println("{}", a);  //prints: [0, 0, 0, 0, 0]
for (auto k = 0U; k < a.size(); ++k) a[k] = (k+1)*10;
std::println("{}", a);  //prints: [10, 20, 30, 40, 50]

Precis som med std::vector, ska du vara försiktigt med hur du accessar enskilda element. Använder du index-operatorn, så finns inga gränskontroller, vilket är ok om du kontrollerar mot metoden size().

auto a = std::array<int, 3>{1,2,3};
int  b[]{10,20,30};
std::println("a: {} @ {}", a, reinterpret_cast<size_t>(a.data()));
//prints: a: [1, 2, 3] @ 140721718715856
std::println("b: {} @ {}", b, reinterpret_cast<size_t>(&b));
//prints: b: [10, 20, 30] @ 140721718715872
a[2] = 33;
a[3] = 44;
a[4] = 55;
a[5] = 66;
std::println("a: {}, b: {}", a, b); //prints: a: [1, 2, 33], b: [55, 66, 30] 😮

Om du vill ha gränskontroll, använd då metoden at() i stället, som kastar ett exception om du försöker nå ett element som inte finns.

try {
    auto a = std::array<int, 3>{1,2,3};
    std::println("a.at(5): {}", a.at(5)); //boom
} catch (std::exception& x) { 
    std::println("ERR: {}", x.what()); //prints: ERR: array::at: __n (which is 5) >= _Nm (which is 3)
}

Samtliga kodsnuttar ovan finns att kika på Compiler Explorer:

Compiler Explorer Try it yourself on Compiler Explorer