views:

174

answers:

5

We all know the basic rules for static array:

int size = 20;
char myArray[size];

is not legal. And.

const int size = 20;
char myArray[size];

is OK.

But, what about this.

int f(const int size)
{
    char myArr[size];
}

void main()
{
   f(2);
   f(1024);
}

MSVC says it is an error, gcc seems to compile and execute it fine.

Obviously, it is not portable, but should it be accepted?

Which compiler does the right thing in that situation?

Also, if it is permited by the compiler, should it be permited by good programming standards/practice?

EDITED: The idea is that I would want stack allocation for the speed, but I would not know at compile time the size of the array. I know that there is some other solutions, and that stack alloc would probably not be a significative optimization, but I think it is an interesting usage.

+9  A: 

No. C++ has no variable-length arrays. C99 does, and gcc allows it via extension.

Use a std::vector.


Assuming you have profiled your application and found this to be a bottleneck, write a custom allocator that allocates from the stack and use that. If not, there's not a problem.

Stack allocation is very fast, but this likely isn't going to be a main concern in a real application. (You should have a custom memory management scheme in place that will performance close in speed to stack allocation.)

GMan
It's not variable length array, the expression that fixes the size of the array is const.
jslap
@jslap: What do you mean? Can you give a more concrete example of what you're trying to do? In your code, `myArr` is a variable length array. The *type* might be const, that doesn't mean the value is a constant expression. Consider: `f(rand());`.
GMan
As I said in my edit, the purpose of the question is not to optimize a particular piece of code. I just want to know if it is an accepatable way of optimizing if I observe it does optimize.I sure know that early optimization is a curse. Actualy, I'm known in my team for saying it all the time.
jslap
@jslap: The argument is const, but not a **compile-time** constant. The size of static arrays is determined at compile-time in C++.
UncleBens
@jslap: I see. I have edited accordingly. Maybe later I'll write a full implementation of a `stack_allocator`, and `auto_allocator` (which switches between the stack and freestore).
GMan
If it is on the stack, can we just increment the stack pointer as we enter the scope of the array, by the amount we want?
jslap
@jslap: In an implementation-specific way, yes. You'd want to wrap it away and turn it into an allocator, though.
GMan
@GMan: I tried with the rand, and it still works. I would think that the important thing is that when you enter the scope, you know the size of the push you need. Which is the case in this example.
jslap
@jslap: You need to define "works". If you're still compiling in gcc with extensions, it's still a VLA. Your code is **ill-formed**, period. No compiler output changes that.
GMan
@GMan: This time I tried it with -std=gnu89. Is this disabling c99 extensions? It still works. How can I check if it is using VLA or not.
jslap
@jslap: Trust me, it is. I know for a fact your code is invalid C++ (all versions), and is only compiling because of an extension. Use the `-pedantic` flag. If you'd like, I can write up a "portable" stack allocator.
GMan
@GMan Thanks, as I said, it was more a theoric question, I don't realy think this kind of optimization would worth it in this particular case anyway. Thank you for the answer... and the offer for the allocator.
jslap
@GMan: Post a question "How to write a stack allocator?" and post your allocator as an answer. Just as with the copy-and-swap idiom.
sbi
@jslap: I keep pointing people at http://y60.artcom.de/redmine/repositories/entry/y60/asl/base/static_vector.h, which is a `std::vector` replacement storing a fixed max number of elements on the stack.
sbi
@sbi: Eh, I probably wouldn't do a self-answer for something like that, it seems to "easy". We were talking about it in chat; I'd probably post it on my blog and edit it into this answer. I think if I did a self-answer one again, it would be "How do I manage resources?", but so far I haven't quite mustered up the motivation. :) Also, for that `static_vector` thing, I think it would be easier to provide a custom allocator than a whole new structure. It would be re-usable too, for other containers.
GMan
@GMan: I dunno. Last time I looked, the only really good article about writing your own allocator google finds is the one by Matt Austern, which is probably a decade old. Admittedly that was long ago, so it might be better by now. As for new allocator vs. new container - there's a pragmatic reason: I think most of the generic code that many people write can survive switching containers, because that's what they all have in mind. Less of the code, however, would survive switching allocators.
sbi
That "How do I manage resources?" made me think. Basically, this is something that would need to go into an FAQ, which you then just point to. I know there is a pretty good C++ FAQ, but SO might provide the means to create a dynamic, collaborative, wiki-style one. What if we could close questions with a pointer to a specific FAQ entry, combined with the possibility to add another hint to that FAQ right away, to cover a so far uncovered aspect brought up by the question just closed? (On third thought, _redirecting_ seems better than closing, because you could still find the question in google.)
sbi
Oh, and http://stackoverflow.com/questions/826569/compelling-examples-of-custom-c-stl-allocators.
sbi
@sbi: A community FAQ seems like a good idea, but it might be hard to manage. I'll certainly consider writing up some form of allocator tutorial, though.
GMan
@GMan: Why do you think it might be hard to manage? As for making up an FAQ: We could invent a new tag for this, maybe `C++FAQ`. What's in there should be CW.
sbi
Bugger. CW was just dismissed, wasn't it? Damn. I didn't consider it all that evil.
sbi
@sbi: Oh, I was thinking one question, with multiple answers per question. What's this you say about CW?
GMan
@GMan: Individual answers could be used to answer individual aspects of a question. Though I'm not sure the voting system would be enough to ensure that not only the wittiest, but also the best and most important answers are voted up. Maybe something like the tag wiki might help, which can only be edited by 1500+ users? As for CW: http://meta.stackoverflow.com/questions/392/should-the-community-wiki-police-be-shut-down/7183#7183
sbi
Heck, I guess just starting to mark classic FAQ questions with a special tag (`c++-faq`?) would help. Merging them, when appropriate, might also be started with right away. As would linking them from the tag wiki page. However, I'd be wary of just starting something that wouldn't have enough backup from the `C++` tag regulars, and I'm sure others would come up with more good ideas.
sbi
You know, I have been thinking about Neil lately. Many others have expressed being tired of answering the same beaten-to-death questions over and over. Maybe doing something about this would give those valued users something to strife for that's not as tiring as answering the same `++i + i++` again and again?
sbi
I've just looked at your profile. (What did you do online 40mins ago? `:)` Isn't it sleeping time over there?) Your "about me" box expresses just this frustration. What do you think about doing something about it?
sbi
@sbi: Yeah. My activity is slowly waning because of these types of questions too. Either SO needs to help out by actually making a *working* search, or we need to start making FAQ questions. They are, after all, frequently asked. Maybe if more C++ regulars showed up in chat we could actually talk about it, but I'm not sure how to get people to join in. Heh, I stay up late. :) Going to bed now, earlier than usual. :P
GMan
@GMan: I'm not sure the chat is good for such discussions. Something like this benefits from a) a good documentation of the discussion so far, b) threading, c) time between arguments, so participants can think about this. Chat fails on all of these. (Can you tell I'm not the chat kind of guy? `:)` You might make me a convert, though.) Well, g'night to you!
sbi
A: 

What you really want isn't quite what you've asked. It seems that you really want a map of numbers to numbers, such that index 2042 holds the value 23, etc.

Since you don't actually know the upper bound of the highest number you might want to use, you will probably have to restructure you code in such a way that it uses a (mathematical) map, where instead of considering 2042 the index of an array holding, you consider 2042 the key to access the value 23.

---- Answer to the can we allocate a static array with an execute time constant below ---

If you want an execute time static array, the best option is to declare the array using the alternative pointer syntax, and then initialize it in a non-static init() like function at the start of the program execution.

If you attempt to allocate the array prior to the execution of main(...) you run the risk of not knowing which static blocks of code are going to be called in what order. Sometimes that makes little difference; but, in your case it seems you need the number to be computed at run time, so the order of the modules becomes important.

By using a non-static method, you esentially guarantee that all the static code is exercised prior to allocating the array.

Edwin Buck
This is not realy what I want to use it for. I want a temporary array in my function that is on the stack. Like for a dynamic programming algorithm for example. Also, see my clarifications about the stack alloc.
jslap
In that case, seems that you'll eventually be pushed into using the alternative pointer syntax for an array and allocating it on the heap. C's compiler was pretty strict about needing to know how much memory it has to lay out in the stack ahead of time (to see if it needed to actually lay it out in the heap as it might not fit in the stack's extra memory in the execution frame). C++ has the same strict standards for arrays too, and since it's a compile time check, it's going to be impossible to do it 100% at run time without some deep, scary magic.
Edwin Buck
What about gcc accepting it and running it fine?
jslap
@jslap: Like I said, it's an extension being adopted from C99.
GMan
+3  A: 

You can use std::array for this. std::array was added in the TR1 extensions and is available in the namespace std or std::tr1 depending on the compiler / standard library version you're using.

#incldue <array>
int main()
{
   std::tr1::array<int,25> myArray;
   //etc...
   myArray[2] = 42;
}

reread the question, regarding stack allocation...

If you want stack allocation, you can use alloca to allocate on the stack instead of malloc(all usual warnings apply).

If you want to a friendlier interface you can implement a custom stl allocator based on alloca and use a std::vector with this (you should read up before implementing).

e.g.:

#include <vector>
template <class T>
class MyStackAllocator
{ // implemented per std::allocator spec
...
}
int main()
{
//allocate a vector on the stack and reserve n items
vector<int, MyStackAllocator<T>> vecOnStack(25);
...
}
Rick
Thanks, but I don't know the size I need before execution.
jslap
see my latest edit.
Rick
+1 for `alloca`. It's unfortunately not part of the C++ standard, nor type-safe, but it is highly portable since it was standardized by BSD and then adopted by virtually all compilers after that. Still, how do you propose to wrap `alloca` with a friendlier interface so that the storage is still valid after the wrapper returns?
Ben Voigt
+1  A: 

The variable length arrays (VLA) are supported by C99, but not by C++. gcc allows it through the extension.

std::vector is doing in C++ what VLA is doing in C99

VJo
How is this different than my answer? You even got the sentence count and layout the same. (Though you're incorrect in saying `vector` is a drop-in for VLA's; `vector` dynamically allocates, VLA's don't.)
GMan
@GMan: More correct to say, `vector` dynamically allocates from the heap, VLAs dynamically allocate from automatic storage (which on most platforms means the call stack, but isn't actually required to be).
Ben Voigt
@Ben: Ah, right. I lose this time.
GMan
@GMan sorry, I started replying, and then I went away to do something. When I came back, I posted. Now I see it is the same response.
VJo
+1  A: 

Correct answer was actually supplied in this thread, so I just want to provide more context to it.

You need to create custom allocator which uses alloca() (or _alloca() in Windows) function for dynamic stack allocation. It's very easy to create one, you can use a typical allocator boilerplate, change allocate() member function to return (pointer)(alloca(size * sizeof(T))); and make deallocate() function empty, because there is no manual stack deallocation. After that you can supply your allocator to the standard containers, e.g. vector<T, stack_allocator<T>>.

There are two caveats, though. Allocate-able stack size can vary significantly, often you have an option to set it at compile time. Visual Studio in 32-bit applications I believe limits it to 1MB by default. Other compilers may have different limits. In 64-bit applications there isn't really any problems as stack can be as large as heap. You will probably need to catch structured exception on stack overrun and convert it to C++ exception.

The second caveat, you should never copy the stack pointers outside of your function, so move semantics, for example, will not work if you pass stack allocated objects to/from the function.

And there is also one inconvenience, you cannot copy containers with incompatible allocators, but you can copy them element by element. E.g.

vector<int> vint;
vector<int, static_allocator<int>> vsint;

vint = vsint; // won't compile, different allocators
std::copy(vsint.begin(), vsint.end(), vint.begin()); // fine
Gene Bushuyev