hen implementing a sequence of elements that needs to grow and shrink dynamically, std::vector is a fine choice. It provides the convenience of a standard container class, including automatic memory management, random access to elements, a uniform interface, and compatibility with standard algorithms.
However, for a sequence whose size is fixed, the performance hit that comes with all that convenience isn’t always justifiable. In particular, a vector incurs the following overhead:
- Nontrivial initialization and destruction. The constructor and destructor of std::vector are relatively costly. This overhead is particularly noticeable when your program creates a large number of vectors.
- Allocation time. Vectors allocate storage for their elements at runtime.
- Space overhead. A vector object typically occupies 32 bytes.
Built-in arrays carry none of this overhead. They allocate their storage statically and have zero space overhead. So why not just use built-in arrays instead for your fixed-sized sequences? Built-in arrays have their own downside: Their security loopholes make them an insecure choice.
Luckily, the C++ Standard Library offers a container-like template called std::array, which offers a secure, efficient, and convenient alternative to built-in arrays?without the overhead of vectors. This 10-Minute Solution shows how to use this powerful alternative for fixed-sized sequences.
How can I implement fixed-sized sequences without the security loopholes of built-in arrays or the noticeable overhead of vectors?
Use std:array as a secure, efficient, and convenient alternative to built-in arrays and vectors for your fixed-sized sequences.
Instantiation and Usage
The std::array class template is defined in the standard header
You instantiate an array object like this:
#include std::array a={1,2,3};
The first template argument specifies the type of the elements. The second argument specifies the array’s size. Notice that the size is mandatory; you can’t deduce it from an initializer-list:
std::array a2={1,2,3}; //error, size missing
The initializer-list is a comma-separated list of up to N elements whose types are convertible to T. If the initializer list contains fewer initializers than N, the remaining elements are default-initialized. Thus, in the example above, a[3] and a[4] are initialized to zero.
Security Enhancements
With respect to security, std::array doesn’t implicitly convert to a pointer. This is to protect your code from inadvertent pointer-related bugs, which are so pervasive when using built-in arrays. If you want to convert std::array to a pointer, you must use the data() member function:
int* p = a; //error, no implicit conversion to int*int* p2 = a.data(); //OKconst int* pc = a.data(); //OK
Similarly, std::array blocks implicit derived-to-base conversions, which might be quite dangerous:
struct Dog : Animal { /* ... */ };struct Cat : Animal { /* ... */ };void trap(array& animals){ animals[3] = new Cat;};array dogs;trap(dogs); /*error: can't convert array to array; */
If this implicit conversion were allowed, dogs[3] would now contain Cat.
Finally, unlike built-in arrays, which decay into pointers at the slightest pretext and thus lose track of their size, std::array always knows how many elements it contains:
int probe(const array* parr){ cout<< parr->size() <size();}
Interfaces to the Standard Library
The std::array template provides the same interface as a standard container class. Therefore, you can use the uniform type names iterator, const_iterator, reference, size_type, difference_type, value_type, and so on:
typedef std::array myints;myints::size_type sz = a.size();myints::iterator it = a.begin();while (it++ != a.end()) cout<<*it<
To assign a single value to every element in the array, use the fill() member function:
array arr; //no initialize list,arr.fill(12); //assign the value 12 to every element
All standard algorithms operate on std::array directly, as with vectors. Consider a function template sum(). It takes a type T that meets the container concept requirements and sums up its elements:
template C::value_type sum(const C& c){ return accumulate(c.begin(),c.end(),0);}array ai5={0,2,4,8,10};vector vi={0,1,3};// ...int sum1 = sum(ai5);int sum2 = sum(vi);
Unlike with built-in arrays, a zero-length std::array is valid, albeit with certain restrictions:
array a0; //OK, no elements
The C++ standard guarantees that when N == 0, begin() == end() == unique value. However, the return value of data() is unspecified, as are the effects of calling front() and back() for a zero-sized array:
int* p = a0.data(); //unspecified; don't do that
As with other standard containers, the member function empty() reports whether the array is empty:
bool has_data =a0.empty();
Compiler Support
The new std::array class template is now supported by several leading compilers, so you should consider using it as an efficient alternative to vectors when dealing with fixed-sized sequences.
To enable C++09 features, you may need to turn on special compilation options, for example, -std=c++0x on GCC. Check your compiler's online documentation for specific details.