In C++, the std::array
is a container class template defined in the Standard Library (part of the C++ Standard Template Library, or STL) that provides a fixed-size array with several advantages over traditional C-style arrays
Why std::array introduced
When you pass a C-style (an array declared using square brackets[]
) to a function in C or C++, you are actually passing a pointer to the first element of the array, and the size information gets lost.
Passing the array to a function:
When you pass a C-style array to a function, you are effectively passing the memory address (pointer) of the first element of the array. This pointer points to the memory location where the array's data begins.
void myFunction(int arr[], int size) {
// ...
}
int main() {
int myArray[5] = {1, 2, 3, 4, 5};
myFunction(myArray, 5); // Pass the array to the function
// ...
}
Loss of Size Information:
Inside the function, you receive the pointer to the array's first element but not the size of the array. You need to explicitly pass the size as a separate argument to the function to work with the array's elements safely.
void myFunction(int arr[], int size) {
// Here, 'size' tells you how many elements are in the array 'arr'.
// ...
}
Due to this loss of size information, its important to be careful when working with C-style arrays in functions. If you access elements beyond the bounds of the array, it can lead to undefined behavior, which is a common source of bugs and security vulnerabilities. This is one of the reasons why C++ introduced the std::array
and the STL container, which provide safer and more convenient alternatives with built-in size informatiion and bounds checking.
Guide:
Header File:
To use std::array
, you need to include the <array>
header.
#include <array>
Declaration:
You declare a std::array
by specifying its data type, name, and size of template parameters.
std::array<DataType, Size> myArray;
For example, to declare an integer array of size 5.
std::array<int, 5> myIntArray;
Initialization:
You can initialize a std::array
at the time of declaration using a list of values enclosed in curly braces.
std::array<int, 5> myIntArray = {1, 2, 3, 4, 5};
Alternatively, you can use uniform initialization:
std::array<int, 5> myIntArray {1, 2, 3, 4, 5};
Accessing Elements:
You can access elements of a std::array
using the []
operator, just like with traditional arrays.
int value = myIntArray[2]; // Access the third element (index 2)
Size:
The size of a std::array
is fixed and can be obtained using its size()
member function.
int size = myIntArray.size(); // Returns 5
Iterating:
You can use range-based for
loops to iterate over the elements of a std::array
.
for (const auto& element: myIntArray){
// Access and manipulate each element
}
Benefits
- std::array provides benefits like type safety, bound checking, better compatibility with standard algorithms and containers compared to C-style arrays.
- It also includes member functions for various operations, like sorting and swapping.
// Sort the elements
std::sort(myIntArray.begin(), myIntArray.end());
Performance:
Typically std::array has the same performance characteristics as C-style arrays since it's implemented as a contiguous block of memory. It's more efficient than some dynamically resizable containers like std::vector
when the size is known and fixed.
Most Commonly used member functions of std::array
.
at(index):
- Returns a reference to the elements at the specified index.
- Performs bounds checking, throwing an
std::out_of_range
exception if the index is out of bounds.
std::array<int, 5> arr = {1, 2, 3, 4, 5};
int value = arr.at(2); // Access the element at index 2
operator[]:
- Returns a reference to the element at the specified index.
- Does not perform bounds checking, so be cautious when using it.
int value = arr[2]; // Access the element at index 2.
front():
- Returns a reference to the first element in the array.
int first = arr.front(); // Access the first element
back():
- Returns a reference to the last element in the array.
int last = array.back(); // Access the last element.
data():
- Returns a pointer to the underlying array.
- Useful when interfacing with C-style functions that a pointer to an array.
int *ptr = arr.data(); // Get a pointer to the underlying array.
size():
- Returns the number of elements in the array.
int size = arr.size(); // Get the size of the array
empty():
- Returns
true
if the array is empty (size is zero), otherwisefalse
. - Returns 1 if the length of array is 0 and 0 if not.
bool isEmpty = arr.empty(); // Check if the array is empty
fill(value):
- Sets all elements of the array to the specified value.
arr.fill(0); // Set all elements to zero
swap(other):
- Exchanges the contents of the array with another array of the same type and size.
std::array<int, 5> anotherArr = {6, 7, 8, 9, 10};
arr.swap(anotherArr); // Swap the contents of arr and anotherArr
max_size():
This function returns the maximum number of elements that the std::array can hold.
Note that the max_size()
function returns a theoretical limit, which may not be achievable in practice due to factors like available memory.
std::array<int, 5> myArray;
size_t maxSize = myArray.max_size(); // The maximum possible size (depends on the implementation)
Iterators
Instead of indices, we can also use iterators to iterate over container. An iterator is a kind of pointing item which can be pointed to an element of a container and has the ability to iterate over the container. It means that if we have an iterator at the beginning of an std::array then, it can go over the entire std::array pointing each item of the std::array.
begin() and end():
- Returns iterators pointing to the first and one-past-the-end elements of the array, respectively.
- Useful for iterating over the elements using range-based for loops or in algorithms.
for (auto it = arr.begin(); it != arr.end(); ++it){
// Access and manipulate each element using 'it'
}
rbegin:
- rbegin() - returns a reverse iterator pointing to the last element of the container (the element at the end).
- It allows you to traverse the
std::array
in reverse order, starting from the last element and moving towards the first element. - This is particularly useful when you need to iterate over a container in reverse without modifying its contents.
std::array<int, 5> myArray = {1, 2, 3, 4, 5};
auto rIter = myArray.rbegin();
// Iterate in reverse order
while (rIter != myArray.rend()) {
std::cout << *rIter << " ";
++rIter;
}
// Output: 5 4 3 2 1
rend:
- rend() returns a reverse iterator pointing to the position before the first element of the std::array.
- It marks the end of the reverse iteration and is often used as stopping condition in loops that traverse a container in reverse.
std::array<int, 5> myArray = {1, 2, 3, 4, 5};
auto rBegin = myArray.rbegin();
auto rEnd = myArray.rend();
// Iterate in reverse order using rBegin and rEnd
while (rBegin != rEnd) {
std::cout << *rBegin << " ";
++rBegin;
}
// Output: 5 4 3 2 1