Why Does C++ Allow Variable Length Arrays That Aren't Dynamically Allocated

Why does C++ allow variable length arrays that aren't dynamically allocated?

Support for variable length arrays (VLAs) was added to the C language in C99.

It's likely that since support for them exists in gcc (to support C99), it was relatively straightforward to add support for them to g++.

That said, it's an implementation-specific language extension, and it's not a good idea to use implementation-specific extensions if you want your code to be portable.

Dynamic memory allocation in C for variable length arrays

int x[n];

Automatic storage duration objects including VLAs are (by most modern implementations) allocated on the stack. There are some problems with the larger objects if they are allocated on the stack (three most important ones):

  1. There is no allocation control unless your program fails when you overflow the stack
  2. Stack is usually much much smaller than the heap. So the size of the array is limited
  3. The lifetime of the array is limited to the lifetime of the enclosing block. You can't return the reference to this array on the function return.

Why aren't variable-length arrays part of the C++ standard?

There recently was a discussion about this kicked off in usenet: Why no VLAs in C++0x.

I agree with those people that seem to agree that having to create a potential large array on the stack, which usually has only little space available, isn't good. The argument is, if you know the size beforehand, you can use a static array. And if you don't know the size beforehand, you will write unsafe code.

C99 VLAs could provide a small benefit of being able to create small arrays without wasting space or calling constructors for unused elements, but they will introduce rather large changes to the type system (you need to be able to specify types depending on runtime values - this does not yet exist in current C++, except for new operator type-specifiers, but they are treated specially, so that the runtime-ness doesn't escape the scope of the new operator).

You can use std::vector, but it is not quite the same, as it uses dynamic memory, and making it use one's own stack-allocator isn't exactly easy (alignment is an issue, too). It also doesn't solve the same problem, because a vector is a resizable container, whereas VLAs are fixed-size. The C++ Dynamic Array proposal is intended to introduce a library based solution, as alternative to a language based VLA. However, it's not going to be part of C++0x, as far as I know.

Why use malloc() when I can just define a variable-length array?

There are at least five benefits to using malloc over variable length arrays.

  1. Most notably, objects created with malloc persist after execution of the current block ends. This means that such objects can be returned (by pointer) to callers of functions. This use is frequent in real-world applications. Arrays created as variable-length arrays cease to exist when execution of their block ends.

  2. Arrays created with malloc can be resized with realloc. Variable-length arrays cannot be resized.

  3. As of the 2011 C standard, variable-length arrays are optional for C implementations to support. A general-purpose C implementation of any quality will support them, but the fact they are optional means code that is intended to be portable must either not use variable-length arrays or must guard against the lack of support by testing the preprocessor macro __STDC_NO_VLA__ and providing alternate code.

  4. Commonly, variable-length arrays are much more limited in size than arrays allocated with malloc. Variable-length arrays are generally implemented using stack space, and stacks are typically limited to some not-large number of mebibytes (although that can generally be increased when building an executable). For objects created with malloc, gibibytes of memory may be available in modern systems.

  5. If creation of an array does fail with malloc, NULL will be returned, and the programmer can easily write code to detect that and deal with it. If creation of a variable-length array fails, the common behavior is for the operating system to terminate the program with some memory error. (Various C implementations may provide means to intercept this error, but it is considerably more of a nuisance than testing the malloc return value for NULL, and it is not portable.)

Why is it a bad idea to use variable length arrays in C++?

Variable length arrays are supported by some compilers as an extension. They are not standard C++. Using VLAs makes your code non-portable.

A better alternative is to use std::vector.

int i = 0;
std::cin >> i;

std::vector<int> array(i);

Is there any overhead for using variable-length arrays?

VLA does have some overhead (compared to "ordinary" named compile-time-sized array).

Firstly, it has run-time length and yet the language provides you with means to obtain the actual size of the array at run-time (using sizeof). This immediately means that the actual size of the array has to be stored somewhere. This results in some insignificant per-array memory overhead. However, since VLAs can only be declared as automatic objects, this memory overhead is not something anyone would ever notice. It is just like declaring an extra local variable of integral type.

Secondly, VLA is normally allocated on stack, but because of its variable size, in general case its exact location in memory is not known at compile time. For this reason the underlying implementation usually has to implement it as a pointer to a memory block. This introduces some additional memory overhead (for the pointer), which is again completely insignificant for the reasons described above. This also introduces slight performance overhead, since we have to read the pointer value in order to find the actual array. This is the same overhead you get when accessing malloc-ed arrays (and don't get with the named compile-time-sized arrays).

Since the size of the VLA is a run-time integer value, it can, of course, be passed as a command-line argument. VLA doesn't care where its size comes from.

VLA were introduced as run-time-sized arrays with low allocation/deallocation cost. They fit between "ordinary" named compile-time-sized arrays (which have virtually zero allocation-deallocation cost, but fixed size) and malloc-ed arrays (which have run-time size, but relatively high allocation-deallocation cost).

VLA obey [almost] the same scope-dependent lifetime rules as automatic (i.e local) objects, which means that in general case they can't replace malloc-ed arrays. They applicability is limited to situations when you need a quick run-time sized array with a typical automatic lifetime.



Related Topics



Leave a reply



Submit