tags:

views:

698

answers:

7

I haven't used C very much in the last few years. When I read this question today I came across some C syntax which I wasn't familiar with.

Apparently in C99 the following syntax is valid:

void foo(int n) {
    int values[n]; //Declare a variable length array
}

This seems like a pretty useful feature, does anyone now if there was ever a discussion on adding it to the C++ standard, and if so why it was omitted? Some potential reasons:

  • Hairy for compiler vendors to implement
  • Incompatible with some other part of the standard
  • Functionality can be emulated with other C++ constructs
  • ???

The C++ standard states that array size must be a constant expression (8.3.4.1)

Yes, of course I realize that in the toy example one could use std::vector<int> values(m); but this allocates memory from the heap and not the stack. And if I want a multidimensional array like:

void foo(int x, int y, int z) {
    int values[x][y][z]; //Declare a variable length array
}

the vector version becomes pretty clumsy

void foo(int x, int y, int z) {
    vector< vector< vector<int> > > values(/*really painful expression here*/);
}

The slices, rows and columns will also potentially be spread all over memory.

EDIT: Looking at the discussion at comp.std.c++ it's clear that this question is pretty controversial with some very heavyweight names on both sides of the argument. It's certainly not obvious that a std::vector is always a better solution.

A: 

You need a constant expression to declare an array in C/C++.

For dynamic size arrays, you need to allocate memory on heap, then manage the liftime of this memory.

void foo(int n) {
    int values = new int[n]; //Declare a variable length array
    [...]
    delete [] values;
}
Tryum
Yes, I know, the question is why is this available in C99 and not C++?
Andreas Brinck
C99 [ PDF @ http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1401.pdf ] has VLAs (Variable Length Arrays).
pmg
I wonder why my code isn't code formated :/
Tryum
Thanks Anders ;)
Tryum
+1  A: 

Use std::vector for this. For example:

std::vector<int> values;
values.resize(n);

The memory will be allocated on the heap, but this holds only a small performance drawback. Furthermore, it is wise not to allocate large datablocks on the stack, as it is rather limited in size.

Dimitri C.
I guess you meant "The memory will be allocated on the *heap*".
Luc Touraille
@Luc: Hm. This is embarrasing :( Anyway, thanks for the correction!
Dimitri C.
+1  A: 

Arrays like this are part of C99, but not part of standard C++. as others have said, a vector is always a much better solution, which is probably why variable sized arrays are not in the C++ standatrd (or in the proposed C++0x standard).

BTW, for questions on "why" the C++ standard is the way it is, the moderated Usenet newsgroup comp.std.c++ is the place to go to.

anon
+2  A: 

This was considered for inclusion in C++/1x, but was dropped (this is a correction to what I said earlier).

It would be less useful in C++ anyway since we already have std::vector to fill this role.

Phil Nash
+1  A: 

If you know the value at compile time you can do the following:

template <int X>
void foo(void)
{
   int values[X];

}

Edit: You can create an a vector that uses a stack allocator (alloca), since the allocator is a template parameter.

Edouard A.
If you know the value at compile time, you don't need a template at all. Just use X directly in your non-template function.
Rob Kennedy
+17  A: 

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 aswell use a static array. And if you don't know the size beforehand, you will write unsafe code.

VLAs could provide a small benefit of being able to create small arrays without wasting space or calling constructors for not used 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 ones 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.

Johannes Schaub - litb
+1 and accepted. One comment though, I think the safety argument is a little bit weak since there are so many other ways to cause stack overflows. The safety argument could be used to support the position that you should never use recursion and that you should allocate *all* objects from the heap.
Andreas Brinck
So you're saying that because there are other ways to cause stack overflows, we might as well encourage more of them?
jalf
@Andreas, agreed about the weakness. But for recursion, it takes a huge number of calls until stack is eaten up, and if that can be the case, people would use iteration. As some people on the usenet thread say, though, this is not an argument against VLAs in all cases, since sometimes you definitely may know an upper bound. But in those cases, from what i see a static array can equally be sufficient, since it would not waste much space anyway (if it *would*, then you would actually have to ask whether the stack area is large enough again).
Johannes Schaub - litb
Also look at Matt Austern's answer in that thread: The language specification of VLAs would probably considerably more complex for C++, because of the stricter type matches in C++ (example: C allows assigning a `T(*)[]` to a `T(*)[N]` - in C++ this is not allowed, since C++ does not know about "type compatibility" - it requires exact matches), type parameters, exceptions, con- and destructors and stuffs. I'm not sure whether the benefits of VLAs would really pay off all that work. But then, i have never used VLAs in real life, so i probably don't know good use cases for them.
Johannes Schaub - litb
@Johannes: there are probably some cases where use of a VLA overcomes your objections. For instance a recursive function, at each step i requires N_i amount of space. The only upper limit I have, S, is on the sum of all N_i, not any individual N_i. So I might know that (a) S is small enough for my stack, so VLA's won't overflow, but (b) S * the max depth of recursion is too big for my stack. Of course this doesn't justify a tricky language feature: I should just allocate S on the stack at the top of the recursion, and pass down a pointer to what's left unused.
Steve Jessop
Ah, I now see that Kaz Kylheku already gave that example on the com.std.c++ thread. The Windows string example given by Alf afterwards actually seems wrong to me, in that for my taste it puts too much responsibility on the caller of a narrow string function, to ensure that there is enough stack left for the library to use a VLA. VLA's don't do what you actually want in that kind of string-conversion situation, which is to allocate on the stack if there's space and from the heap if there isn't. But I guess on Windows, there's "room" on the stack iff there is on the heap, pretty much.
Steve Jessop
@Johannes: "benefit of being able to create small arrays without wasting space or calling constructors for not used elements". A boost::array-like container which takes a runtime parameter for how many element to initialize of the allocation would be excactly as useful (except for maybe in recursive algorithms). Any runtime sized array ought to have a max number of elements, and allocating this amount of stack space immediately will give you your un-avoidable crash sooner, which is good.
Viktor Sehr
@Viktor, indeed. But a maximally sized array will also call all constructors, which might not be what you want. I think the array-like container is a good compromise between changing the language to introduce VLAs (which i believe is a large change), and having no support at all.
Johannes Schaub - litb
@Johannes: No, what I mean is; if the array is a wrapper around a primitive type, (ie unsigned char[N * sizeof(T)]) the array can call the placement new/constructor for the number of elements in the runtime size variable. (if N denotes the static maximum size, T the type and n the runtime size, your constructor does something like for(i...n) {new (this + sizof(T)*i) T();}
Viktor Sehr
@Viktor, i agree. Such a thing would be useful, and you could provide `N` as a template parameter as the maximal count of items. And writing it will be easier in C++0x with the various alignment tools available (`alignof`, etc).
Johannes Schaub - litb
+1  A: 

You could always use alloca() to allocate memory on the stack at runtime, if you wished:

void foo (int n)
{
    int *values = (int *)alloca(sizeof(int) * n);
}

Being allocated on the stack implies that it will automatically be freed when the stack unwinds.

Quick note: As mentioned in the Mac OS X man page for alloca(3), "The alloca() function is machine and compiler dependent; its use is dis-couraged." Just so you know.

PfhorSlayer