Skip to Content
Course content

75: std::array for Fixed-Size Arrays

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was working on a small RPG prototype earlier today, and I needed a way to store a character's core attributes—Strength, Dexterity, and Intelligence. Since every character always has exactly these three stats, I didn't need a dynamic list. I just needed a fixed-size container.

The old way: C-style arrays and the decay problem

My first instinct was to just use a plain C-style array. It's the most basic tool we have. I wrote a quick function to print the stats, and this is where I hit the classic C++ annoyance:

int stats[3] = {10, 15, 8};

void printStats(int arr[]) {
    // Wait, how big is arr? 
    // I can't use sizeof(arr) here because it decayed to a pointer.
}

If you've spent any time with C-style arrays, you know exactly what I'm talking about. The moment I pass stats into printStats, it "decays" into a pointer to the first element. The size information is just... gone. To fix this, I'd have to pass the size as a second argument: void printStats(int arr[], size_t size). It's tedious, it's error-prone, and frankly, it feels like we're writing code from 1998.

Switching to std::array

I decided to swap this out for std::array. If you haven't used it yet, think of it as a thin wrapper around a C-style array that actually remembers its own size and behaves like a proper C++ object. Here is how I refactored that snippet:

#include <array>
#include <iostream>

void printStats(const std::array<int, 3>& arr) {
    // Now I can actually use .size()!
    for (size_t i = 0; i < arr.size(); ++i) {
        std::cout < "Stat " < i < ": " < arr[i] < "\n";
    }
}

int main() {
    std::array<int, 3> stats = {10, 15, 8};
    printStats(stats);
    return 0;
}

Notice the type: std::array<int, 3>. The size is part of the type itself. This is a huge win for the compiler—it knows exactly how much memory to allocate on the stack, and it can optimize the heck out of it. I'm passing it by reference (const std::array<int, 3>&) because, unlike a pointer, a std::array is a value type. If I passed it without the &, C++ would copy the entire array every time the function was called. For three integers, that's trivial. For 1,000 integers? That's a performance nightmare.

Safety first: .at() vs []

While I was testing this, I wondered what would happen if I tried to access a stat that doesn't exist. I tried accessing index 3 (the fourth element) using the square bracket operator:

std::array<int, 3> stats = {10, 15, 8};
std::cout < stats[3] < "\n"; // Out of bounds!

The program didn't crash immediately; it just printed some garbage value from a random spot in memory. This is "Undefined Behavior," and it's the primary cause of those impossible-to-track bugs that keep you up until 3 AM. If I want the program to actually tell me when I've messed up, I should use the .at() method instead:

try {
    std::cout < stats.at(3) < "\n";
} catch (const std::out_of_range& e) {
    std::cerr < "Caught an error: " < e.what() < "\n";
}

The .at() method does bounds checking. It's slightly slower than [], but during development, that safety is worth every single nanosecond. I usually use .at() while I'm prototyping and only switch to [] in the final release for hot paths where performance is absolutely critical.




📋 Practical Task

Implementing a 4-Slot Equipment Loadout

Create a program that manages a character's equipment slots. You must use std::array to ensure the character can never have more or fewer than exactly 4 equipment slots.

  • Define a std::array of strings with a size of 4 to hold item names (e.g., "Iron Sword", "Leather Shield", etc.).
  • Initialize the array with four starting items.
  • Create a function called updateEquipment that takes the array by reference and two integers: the slotIndex and a new itemName.
  • Inside updateEquipment, use the .at() method to update the item. Wrap this call in a try-catch block to handle cases where an invalid slot index is provided.
  • In your main function, call updateEquipment once with a valid index and once with an invalid index (like 5) to demonstrate that your error handling works.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.