Let's play a game of guessing! What can you tell about the following function?
char* vector_advance(char* val);
Should return values be deallocated by the programmer or not? Does the function attempt to deallocate the input parameter? Should the input parameter be zero-terminated, or should the function assume that the input parameter has a specified width?
Now, let's make the task harder! Take a look at the following line:
char ( &vector_advance( char (&val)[4] ) )[4];
Do not worry. I've also been scratching my head for half an hour before getting an idea of what is happening here. vector_advance
is a function that accepts and returns an array of four elements. Is there a way to write such a function clearly?
We can rewrite the function like this:
#include <boost/array.hpp> typedef boost::array<char, 4> array4_t; array4_t& vector_advance(array4_t& val);
Here, boost::array<char, 4>
is just a simple wrapper around an array of four char
elements.
This code answers all the questions from our first example and is much more readable than the code from the second example.
boost::array
is a fixed-size array. The first template parameter of boost::array
is the element type and the second one is the size of an array. If you need to change the array size at runtime, use std::vector
, boost::container::small_vector
, boost::container::stack_vector
, or boost::container::vector
instead.
The boost::array<>
class has no handwritten constructors and all its members are public, so the compiler will treat it as a POD type.
Let's see some more examples of the usage of boost::array
:
#include <boost/array.hpp> #include <algorithm> typedef boost::array<char, 4> array4_t; array4_t& vector_advance(array4_t& val) { // C++11 lambda function const auto inc = [](char& c){ ++c; }; // boost::array has begin(), cbegin(), end(), cend(), // rbegin(), size(), empty() and other functions that are // common for standard library containers. std::for_each(val.begin(), val.end(), inc); return val; } int main() { // We can initialize boost::array just like an array in C++11: // array4_t val = {0, 1, 2, 3}; // but in C++03 additional pair of curly brackets is required. array4_t val = {{0, 1, 2, 3}}; array4_t val_res; // it is default constructible val_res = vector_advance(val); // it is assignable assert(val.size() == 4); assert(val[0] == 1); /*val[4];*/ // Will trigger an assert because max index is 3 // We can make this assert work at compile-time. // Interested? See recipe 'Check sizes at compile-time' assert(sizeof(val) == sizeof(char) * array4_t::static_size); }
One of the biggest advantages of boost::array
is that it does not allocated dynamic memory and provides exactly the same performance as a usual C array. People from the C++ Standard committee also liked it, so it was accepted to the C++11 standard. Try to include the <array>
header and check for the availability of std::array
. std::array
has a better support for usage with constexpr since C++17.
- Boost's official documentation gives a complete list of the
Boost.Array
methods with a description of the method's complexity and throw behavior. It is available at the following link: http://boost.org/libs/array. - The
boost::array
function is widely used across recipes; for example, refer to the Binding a value as a function parameter recipe.