devxlogo

Spruce Up Your Built-in Arrays

Spruce Up Your Built-in Arrays

++ pundits recommend that you replace built-in arrays with st::vector across the board. Sometimes however, built-in arrays are unavoidable due to their unsurpassed efficiency or because your app must interact with external software e.g., a relational database or an XML schema. In the following sections I will present two techniques for enhancing this mundane feature: an array wrapper template, and a variable length array. When used judiciously, these enhancements enable you to use built-in arrays without sacrificing STL compatibility and without resorting to manual memory management, respectively.


How to use built-in arrays without compromising STL compatibility? Also, how to create an array whose dimensions are determined at runtime without the pains of dynamic memory allocation?


Use an array wrapper template and C99’s variable length arrays, respectively.

Problem Analysis
When you need a container that grows and shrinks dynamically, st::vector is unquestionably the right choice. However, sometimes st::vector is used instead of a built-in array only for the sake of interoperability with other Standard Library components. Performance-wise, this technique isn’t ideal: st::vector involves complex construction and destruction operations, it allocates elements on the free-store (even when their number is fixed and known at compile-time), and it isn’t exactly a lightweight class. What you really want is the compactness and speed of built-in arrays, while still benefiting from an STL-like interface. You can achieve this by using a wrapper class template.

Step 1: Array Wrapping
The following array_wrapper class template, originally presented by Bjarne Stroustrup, wraps a built-in array in a class that has no additional data members and therefore incurs no space overhead. Unlike ordinary STL containers, array_wrapper allocates its array statically on the stack, just as built-in arrays do. Most importantly, it provides the standard interface that other STL components recognize:

template  struct array_wrapper{//uniform typedefs used in STL algorithms and containers typedef T value_type; typedef T* iterator; typedef const T * const_iterator; typedef T& reference; typedef const T& const_reference;T v[sz]; //the actual array; no other data members here// member functions of typical STL containersoperator T* () {return v;}reference operator[] (size_t idx) {return v[idx];}const_reference operator[] (size_t idx) const {return v[idx];}iterator begin() {return v;}const_iterator begin() const {return v;}iterator end() {return v+sz;}const_iterator end() const {return v+sz;}size_t size() const {return sz;}};

This class is designed for utmost efficiency. It has neither a constructor nor a destructor. Additionally, all its member functions are inlined.

You initialize an array_wrapper as you would a built-in array. The resulting object can be used wherever a built-in array is expected:

void func(int *, int sz); // C function //wrap an array of 20 int's & initialize all members to 0array_wrapper  arr={0};  func(arr, arr.size()); //using T* conversion operator

Let’s see how advantageous STL compatibility is. The following example uses the copy() algorithm and an ostream_iterator to display the contents of arr on the screen?as if it were an STL container:

copy(arr.begin(), arr.end(),  ostream_iterator(cout, " "));

The C++98 Standard Library doesn’t define this class template. However, it will be added in the next revision round. In the meantime, you can download a similar class from Boost or roll your own.

Step 2: Variable Length Arrays
In C++ and pre-C99 dialects of C, an array’s dimension must be a constant integral expression so that its size can be calculated at compile-time. In C99 this rule was relaxed. Now an array’s dimension must be an integral expression?not necessarily a constant one. This allows you to declare a variable-length array, which is an array whose dimension(s) are determined at runtime. Here is an example:

void func(int dim)  { int arr[dim]; // dim isn't a constant; C99 only cout<< sizeof (arr) <

The arr may have different dimension in every func() call. For example:

int main(){ size_t elements; cout<<"how many elements? "<> elements; func(elements);}

Most compilers require that you turn on C99 support explicitly to use this feature. For example, in GCC you need to use the "-std=c99" command option. The C99 standard also modifies the semantics of the sizeof operator. When applied to variable length arrays, it computes their size at runtime. This is why the cout expression inside func() displays the correct size of arr on every invocation.

A Different Dimension
The array_wrapper class doesn't replace st::vector; rather, it serves as an efficient, STL-compatible wrapper for built-in arrays. C99's variable length arrays are another variant of the traditional built-in arrays. The only difference is that in this case the array's dimension is determined at runtime. In modern operating systems, a typical process has a stack size of 2 MB, which makes variable length arrays more useful than they would have been in the days of 16-bit computing. Think for example of a thumbnail viewer that reads an image from a disk file. Instead of mucking with dangling pointers, memory leaks, delete versus delete[] and exception handling, you can read the size of each image from the disk, create a variable length array of the appropriate size and be done. This feature is particularly appealing to C programmers, although C++ programmers can also add it to their arsenal.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist