12

In the past whenever I needed to create an instance of a class I would use new to allocate it on the heap (except for stl classes, and math classes like vec3 and mat4).

However, I was just looking critically at some of my code and realized that technically I could just be making these classes on the stack instead. They're not very big, don't need to be modified outside of their current scope, etc. When I (occasionally) need to pass them to another function I can use a reference as easily as I could pass a pointer.

In the past I always defaulted to allocating on the heap, and only used the stack in certain cases, however now I'm wondering if it would have been better to default to allocating on the stack, and only use the heap when

  • a pointer is really needed (ie the lifetime of the object to outlast the scope of declaration)
  • the class or array is too big for the stack
  • inheritance requires it (abstract base class/interface)
  • something else?

Which also raises the question: how big a class is too big (roughly) to reasonably allocate on the stack? (assuming we're working on, at minimum, smartphones, and going up to high end desktops) Am I just worrying unnecessarily about stack size constraints? (probably, as long as we're not talking large arrays, and no class is going to be even close to a kilobyte)

quantum
  • 3,672
  • 29
  • 51
zacaj
  • 1,987
  • 1
  • 19
  • 39
  • I would add, when you want the lifetime of the object to outlast the scope of declaration. Out of your list, I would remove all except possibly the class size argument. – juanchopanza Sep 08 '12 at 17:48
  • Not a direct answer, but stack allocation does have some true advantages over heap allocation (e.g. speed, automatic scope, etc.) [This answer](http://stackoverflow.com/a/11044838/195701) enumerates a few of them. – Miguel Sep 08 '12 at 17:50
  • @juanchopanza I considered this to be one of the cases where 'a pointer is really needed' – zacaj Sep 08 '12 at 18:02
  • "how big a class is too big (roughly) to reasonably allocate on the stack" - this is completely implementation-dependent. For some implementations (microcontrollers and so on), 4k of stack is massive. For others, it's absolutely trivial. The standard provides no means for portable code to figure out which it is, and behavior when you use too much stack is that the program is unceremoniously terminated *if you're lucky*. You just have decide whether or not you're writing code that's "low stack friendly", then take your chances. – Steve Jessop Sep 08 '12 at 18:03
  • @stevejessop I'm working on a game engine, so I'd imaging smartphone level arm6/7 based systems would be on the lower end stack size-wise – zacaj Sep 08 '12 at 18:05
  • @zacaj: they were when I worked on them, but that was some years ago and it was on Symbian. Default stack size was something like 16k I think, but we generally pushed the boat out and configured our binaries to request more. If you're writing for a particular platform then it's something you can look up and/or test, but when you're writing portable components it can be tricky to judge what some unknown person in future trying to integrate your code on a new platform will think is excessive. – Steve Jessop Sep 08 '12 at 18:08
  • ... For non-trivial OSes, the toolchain lets you configure stack size of the main thread, likewise when you run a new thread you say how much stack you want. So if you use "a lot of stack" for the platform it doesn't necessarily mean your code will be impossible to port, but occasionally it will be inconvenient. I wouldn't expect smartphones to have really tiny limits on how much stack you can configure, given they have tens of MB of RAM, but I don't do that any more so I *know* nothing :-) – Steve Jessop Sep 08 '12 at 18:11
  • @zacaj has nothing to do with "needing a pointer". It has to do with needing an object that lives beyond the local scope. – juanchopanza Sep 08 '12 at 18:12
  • @juanchopanza If it lives beyond the local scope and it's on the stack it would be deallocated, therefore it "needs a pointer" – zacaj Sep 08 '12 at 18:22

4 Answers4

8

Your default behavior should be:

If the lifespan of the object is consistent with a specific scope
ie easily determined at compile time

then it should be an automatic storage duration object (stack like)

If the lifespan of the object is defined at runtime and extends beyond the current scope

Then it should be a a dynamic storage duration object (heap like)

Note: All dynamic storage duration objects should have their lifespan controlled by wrapping them in a an appropriate RAII class. Usually this means: For single objects a smart pointer, while multiple objects end up in a container.

I hate to see things defines as stack Vs heap. As it does not convey the real semantics of the situation.

 int x;       // its on the stack
 struct X
 {
     int x;   // Is this a stack or heap object?
 }            // It depends on its parent.


 // But in both cases it is an automatic storage duration object.
 // In both cases the lifespan's are well defined.
 //     The first is defined by the scope it is declared within.
 //     The second is defined by the lifespan of its parent.

You should be thinking in terms of automatic/dynamic 'storage duration' objects. This conveys the correct semantics of the language.

Note there are two other types of variable thus making four different types of variable. automatic/dynamic/static/thread 'storage duration' objects.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • is using smart points pretty much industry standard for all dynamic allocation nowadays? – zacaj Sep 08 '12 at 18:09
  • @zacaj: You would hope so (but don't fall into the trap that smart pointers are the only mechanism (think containers)). For people that write real modern C++ yes. But there are still a lot of people that write C with a C++ compiler (AKA as C-with classes). But all good exception safe C++ code is written using smart pointers. – Martin York Sep 08 '12 at 18:12
5

I prefer to allocate on the stack, for two reasons. First, all else being equal, it is faster than heap. Also, the deallocation happens automatically, I don't need to rememeber to delete it (of course, there are auto_ptrs and such to help with that).

a pointer is really needed

It is OK to pass a pointer to an object on the stack. Just make sure the user of that pointer does not access the object after its lifetime expires.

the class or array is too big for the stack

Only for really big things should this matter. You've probably got 1MB of stack, so you can put about 1000 1KB objects before there's a problem.

inheritance requires it

Why would it?

something else?

The lifetime required of the object is longer than the lifetime of the stack frame. This is the principal reason to allocate on the heap.

Keith Randall
  • 22,985
  • 2
  • 35
  • 54
  • "Why would it?" - factory functions that return a difference concrete class according to their parameters and/or some configuration. It's not *exactly* the inheritance that requires it, it's the fact that the user only knows the base class. – Steve Jessop Sep 08 '12 at 18:00
  • @SteveJessop: In that case I would just say that the API requires it (all the constructors, if any, are private). It has nothing to do with inheritance. – Keith Randall Sep 08 '12 at 18:04
  • @stevejessop this is pretty much what I meant. I have a lot of abstract base classes that have many different implementations, in which case a pointer would be required – zacaj Sep 08 '12 at 18:08
1

When should a class be allocated on the stack instead of the heap?

Whenever possible and not a great inconvenience. There will be exceptions, but to answer your question as a general rule: When creating an instance, new/new[] should be typed less than one percent of the time.


a pointer is really needed (ie the lifetime of the object to outlast the scope of declaration)

Yes, in appropriate cases. Judging by your use of the heap described in the OP, this is likely going to be necessary far less often than you believe.

the class or array is too big for the stack

Yes, but that should not be much of a concern -- a class that large typically indicates that something is fundamentally wrong with your class. Client friendly classes might consider creating those huge, fixed sized arrays on the heap.

inheritance requires it (abstract base class/interface)

In some cases (e.g. where an abstract factory or deep clone of polymorphic type is present), but then it is the factory that creates the type, and the problem is often shifted away from your program's use of the stack before you can consider it.

something else?

No


The reasons:

  • it's clear, succinct, and its lifetime and scope are well determined.
  • less resource consumption.
  • fewer memory related bugs or things that could go wrong.
  • speed. the stack allocation is very fast. fewer locks.
justin
  • 104,054
  • 14
  • 179
  • 226
-2

You allocate on the heap only when you need to dynamically allocate the memory. Meaning you do not know how much you need to allocate at compile time. You allocate on the stack all other times

tsmyelin
  • 7
  • 1
  • -1 for "Meaning you do not know how much you need to allocate at compile time." This is false. The OP gives some other situations when you need to allocate on the heap, such as allocating something that's too big for the stack. You may know at compile-time that you need an array of 10 million ints, but that's too big for the stack on most operating systems, so you should allocate it on the heap. – Adam Mihalcin Sep 08 '12 at 17:55
  • -1 This is not a good answer - sometimes the stack will simply not be large enough. – mathematician1975 Sep 08 '12 at 17:56
  • You may need to pass the object in the system, which means your function will return the object, but it will not be valid any more. – roni bar yanai Sep 08 '12 at 17:58
  • See also the last two sentences of Keith Randall's answer - object lifetime is a key consideration. – Bryan Sep 09 '12 at 14:53