devxlogo

std::array: The Secure, Convenient Option for Fixed-Sized Sequences

std::array: The Secure, Convenient Option for Fixed-Sized Sequences

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 , and it supports random access iterators. An instance of array stores N elements of type T. The elements are stored contiguously on the stack (as opposed to std::vector, which stores elements on the free-store). Also, std::array has implicitly-declared special member functions (constructor, destructor, copy constructor, and assignment operator) with minimal runtime overhead.

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){ coutsize() 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

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.

devx-admin

Share the Post: