3

I'm having a hard time seeing how you can safely allocate a stack located array in C++.

Normally people do this:

int a[hugeNumber]{0};  //declare,allocate,inti to 0.

That can easily fail due to stack overflow.

I would like to split up the declaration and allocation somehow and have the allocation in a try catch.

Obviously this will not work because the array would not be accesible outside of try.

try{
    int a[hugeNumber];
}
catch(std::bad_alloc& e)
{
}

//code here can't use a because of scope.

If you can only allocate heap based arrays in a safe way by separating declaration and allocation then stack based arrays are unusable by production code, no?

I consider this mostly a mental exercise. I've been thinking about it and I don't see any place make the point. hugeNumber in reality is relative. Realistically even a normal number can cause a failed allocation and since there does not appear to be a way to safely allocate a stack based array I am asking the obvious... "Can stack based arrays be used in production code?". I asked just in case there is some syntax I'm not aware off. I really appreciate the input.

code
  • 1,056
  • 10
  • 22
  • 1
    It's certainly difficult to use large stack-allocated arrays in portable code, at any rate. As long as you don't have recursion involved, you can do some testing to find the greatest stack depth used, and then tell the linker how much stack space you need allocated. – Jerry Coffin Jan 09 '18 at 02:08
  • 2
    Just use `std::vector a(hugeNumber);` – Ed Heal Jan 09 '18 at 02:08
  • 1
    I don't think stack overflow throws exception. –  Jan 09 '18 at 02:14
  • @EdHeal: Though that does involving initializing all the entries immediately, which a raw array need not do for POD types. That said, large enough heap allocations may draw directly from the OS (which gives back zeroed memory "for free"), and a standard lib which takes advantage of this may be able to skip the zeroing work in that case. – ShadowRanger Jan 09 '18 at 02:18
  • I consider this mostly a mental exercise. I've been thinking about it and I don't see any place make the point. hugeNumber in reality is relative. Realistically even a normal number can cause a failed allocation and since there does not appear to be a way to safely allocate a stack based array I am asking the obvious... "Can stack based arrays be used in production code?". So far it seems no one seems to be able to suggest a safe way to do this. I asked just in case there is some syntax I'm not aware off. I really appreciate the input. – code Jan 09 '18 at 02:25
  • @code You might want to [edit] to clarify your intent as stated in the comments. – Passer By Jan 09 '18 at 02:26
  • @Passer By: Thanks, done. – code Jan 09 '18 at 02:28
  • *"Realistically even a normal number can cause a failed allocation"* We must be living in different realities. In my experience, I've never seen this happen for a reasonably sized arrays (where "reasonable" is perhaps a few dozen elements). It's either oversized arrays (use `vector` so the data goes on the heap) and/or deep recursion (reimplement as an iterative algorithm using an explicit stack). – Igor Tandetnik Jan 09 '18 at 02:30
  • I think if you can allocate an array of size `n` inside a try block, you can (probably) allocate an array of size `n` outside the block. So `try{ int a [n]; } catch { std::cout << "No\n"; return 0; } int a[n]` would probably be safe. – user202729 Jan 09 '18 at 02:33
  • I like the use of `probably`! :-) – Ed Heal Jan 09 '18 at 02:34
  • Just tested it, segmentation fault even inside try-catch block. [Try it online!](https://tio.run/##XYqxCsIwFEXnvK941KUOBl3b2kkc@wPqEF6CBtokJK@gSL89knbzLgfuORTC4UmU8846GmdtsLM@cTRq6gGsYyTvEpt3iDjgGU/Hbe0mJ2VdvccvCI6fAlFehbfh0YJYkBTTC2sp5RqJxLppyM@MXYfVVdnR6LurSgt/8uKdWdUCkPMP "C++ (gcc) – Try It Online") – user202729 Jan 09 '18 at 02:37
  • [It seems that you can't catch stack overflow](https://stackoverflow.com/questions/1578878/catching-stack-overflow-exceptions-in-recursive-c-functions)... (that's another case, but it should be similar) – user202729 Jan 09 '18 at 02:39
  • @Igor: What got me thinking about this is I was doing some testing and in a 4GB machine I found that the stack blew at 500,000 ints. Prob it would have blown at 500,000 int elements with a 32GB machine also. My point is that I did not know what the magic number was. In a different program it could be 50,000 ints. Both OS and competing allocationsin an application influence the magic number. So it is not obvious what is OK. 12 ints is "probably" ok... sure... but what about 1000 long long? If the app is military or finance grade production level code... it's like rolling the dice, no? – code Jan 09 '18 at 02:40
  • The main point here is "this is a mental exercise". Also you can resize the stack by (Windows) pass some argument to the linker or (Linux) ulimit. – user202729 Jan 09 '18 at 02:42
  • @code - It is called testing. I would think that under 1000 is ok. Otherwise static or heap – Ed Heal Jan 09 '18 at 02:43
  • @EdHeal "test"... what? how? StackOverflow can't be caught. – user202729 Jan 09 '18 at 02:43
  • [Related](https://stackoverflow.com/questions/53827/checking-available-stack-size-in-c). There are both Linux and Windows method. – user202729 Jan 09 '18 at 02:45
  • You run various tests with various scenarios - testing it to destruction. It the software crashes it fails. BTW. If you are so inclined you can use static on the outset and write the software to not use the heap at all. This is used in power stations etc. – Ed Heal Jan 09 '18 at 02:48
  • @EdHeal "mental exercise"... / You mean, manually increase the stack size the program try to allow? Can the program do that by itself? I don't think so. – user202729 Jan 09 '18 at 02:49
  • @Ed Heal: So the answer we seems to be arriving at is, "no, can't be done safely". Because to do the level of testing you suggest is an enormous time sync and even then there is no "guarantee". I'm aware you can assure heap allocated arrays are allocated correctly and also that you can do the same for vector and other STL data structs. I was just wondering If I was ignorant of some way to use stack based arrays safely. – code Jan 09 '18 at 02:52
  • @code - You need to do the testing. What do you mean by "time sync"? Any serious project spends about 40% of effort on testing – Ed Heal Jan 09 '18 at 02:56
  • Personally, I wouldn't call 1000 elements - let alone 500,000 - a "normal" size for an array on the stack. Where you need a 1000 elements, you probably actually need `O(N)` elements where `N` is the size of the input - that's not a proper use of stack memory. Something like `int days_in_month[12] = {31, 28, 31, ...};` is fine though. – Igor Tandetnik Jan 09 '18 at 03:00
  • @Ed, what I mean is that we can avoid the problem if we are cognisant of it by using vector or a heap allocated array. So there is not point doing it the hard way and spends hours/days testing what the magic number statistically is likely to be. I just wanted to confirm the issue with stack allocated arrays... just in case I was missing something. But apparently this is an issue and now that we know, we can bypass the issue easily buy not using stack allocated arrays in production level code. – code Jan 09 '18 at 03:01
  • @Igor. Right, i agree. Chances are... that is fine. But some programmers would use it for 500 or even 1000. Tbh, sometimes I have. And it was fine. I didn't realize just how dangerous this is until I thought about it. Normally I gravitate towards heap by habit. I was just wondering if there was some syntax to deal with this issue. Apparently there is not, and you must take a chance if you want to use a stack allocated array. – code Jan 09 '18 at 03:05
  • 1000 is the upper limit IMHO. Good programming skills is the way to avoid the problem along with good and rigorous testing – Ed Heal Jan 09 '18 at 03:10
  • 2
    Some programmers could leak memory, or dereference dangling pointers - there's no shortage of dumb things one can do in C++. I don't think misuse of stack arrays ranks very high on the list of common mistakes. – Igor Tandetnik Jan 09 '18 at 03:11
  • I've just read that [stack allocation is faster than heap allocation](https://stackoverflow.com/questions/161053/which-is-faster-stack-allocation-or-heap-allocation?rq=1)... – user202729 Jan 09 '18 at 03:25
  • Do not get into the mindset of optimisation without a reason. You can spend ages on microoptimisation without achieving much. Better to write readable code in the first place and find out where the code is spending most of its time. Do not forget the 80-20 rule – Ed Heal Jan 09 '18 at 03:32
  • @igor, true. I noramally use heap. Never had a prob with stack allocated arrays cause I typically keep them small. Because of that I never verified the allocation. I allways assumed there was a way to safely declare and then allocate in a separate step stack allocated arrays. It is only now that I realized that there actually is no syntax to do that. Largely due to the fact that it is not possible to syntactically separate the declaration and the allocation for a stack allocated array. I thought I wasn't aware of the syntax to do so... – code Jan 09 '18 at 03:35
  • @Ed. Right. I'm not obsessing just exploring my ignorance. :) – code Jan 09 '18 at 03:38

2 Answers2

6

Realistically even a normal number can cause a failed allocation and since there does not appear to be a way to safely allocate a stack based array I am asking the obvious...

This applies to all automatic variables, not just arrays. If you cannot be sure that there is enough stack memory for a "normal" sized array, then how could you be sure if there is enough memory for a single object?

Stack memory is limited, but it is still huge compared "normal" sized objects and arrays.

Can stack based arrays be used in production code?

Sure. Automatic arrays can be used in production code, just as any automatic objects can (and in fact, must) be used in production. You simply cannot use huge automatic objects.

Exactly where the practical size limit of an automatic object is, is greatly situational. The more automatic storage you use, the more relevant it is to analyse the maximum stack size used.

To avoid stack overflow in production, there should be testing before deployment. There are tools that will detect a stack overflow if it occurs in a test run.


Obviously this will not work because the array would not be accesible outside of try.

try{
    int a[hugeNumber];
}
catch(std::bad_alloc& e)
{
}

It will also not work because stack overflow does not throw an exception.


I asked just in case there is some syntax I'm not aware off.

There is no syntax to "try" allocating automatic objects (including arrays). There is also no way in C++ to check how much memory there is available for automatic storage although there might be system specific ways.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Right, fairly good answer based on discussion in the thread. I think there is a diff between single item stack objects like int and an array of items. Namely that you will unlikely run into a scenario that you will ever write a code where you have enough single items to blow the stack. That code would have so many variables it would be humanly untraceable. On the other hand, nothing prevents you from declaring a stack allocated array of any size you wish. Really what we're asking here is it possible to seperate declaration and allocation or use some other scheme to verify succ allocation. – code Jan 09 '18 at 04:14
  • Most people don't bother verifying alloc. The q was, "is it possible?". The answer is, it is not. It is the lack of possibility that I was asking. Not if we should or should not take a chance. I blew the stack at 1MB. Could have blown it at much less with certain sys. If you can make the ans a bit more clear to reflect this, I would like to give you the points cuz your ans is nice and will serve others well. I don't think, "yes, you can use stack allocated arrays safely because their just like any other stack variable, just keep the size 'small' "... really does justice to the issue. – code Jan 09 '18 at 04:23
0

I would like to split up the declaration and allocation somehow and have the allocation in a try catch.

That requires dynamic allocation using new, eg:

int *a = nullptr;
try
{
    a = new int[hugeNumber];
}
catch(const std::bad_alloc &e)
{
    ... 
}
...
delete[] a;

Or:

std::vector<int> a;
try
{
    a.resize(hugeNumber);
}
catch(const std::bad_alloc &e)
{
    ... 
}
...
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770