0

Spoiler just contains background and context

! This post mentions that, to get around the fact that when object goes out of scope it is deallocated, simply return the object the stack-allocated object so it remains in scope. This apparently makes a copy of the object on the stack somewhere else. This guy even confirms that you should always prefer allocating to stack. In C++, using something like:

! Object* my_object = new Object();

! Dynamically instantiates an object to the heap, yet ! Object my_object = Object();

! Instantiates an object on the stack. The stack is limited in size whereas the heap is practically not (other than physical limits). But also, according this this post, stack access time is much faster, and of course the deallocation is automatic when it goes out of scope.


I'm trying to create an application where speed is absolutely critical, can't I just instantiate all of my objects on the stack within main, and simply save every instantiation that's within a nested scope to an outside container?

I tested this myself using a simple Node class that contains the property "id". I instantiated the nodes on the stack, put them in a vector so they don't get deallocated, then (just to check) I allocated new items to the stack and then checked to make sure the data to the previous allocations still existed. Can I continue to implement this on a somewhat large-scale problem?

int main()
{
  vector<Node> stack_nodes;
  for (int i = 0; i < 2; ++i)
  {
    stack_nodes.push_back(Node(i)); // push newly copied stack-allocated objects so they don't die 
  }
  Node new_node1 = Node(3); // allocate two more to test stack memory overwriting 
  Node new_node2 = Node(4);
  cout << stack_nodes.at(1).getID(); // outputs 1! It's still there?
  return 0;
}

EDIT: See comments below. When you return the stack-allocated object from the scope it was created in, a copy of said object is created. Is that copy also on the stack? If I assign that copied object to a vector declared in the scope of main, will that object still be on the stack?

Community
  • 1
  • 1
  • `can't I just instantiate all of my objects on the stack within main, and simply save every instantiation that's within a nested scope to an outside container?` yes, of course you can. What exactly is your question? , the code you wrote is perfectly fine. – Abhishek Gupta Jan 15 '15 at 03:21
  • 2
    *"outputs 1! It's still there?"* -- I take it that surprises you? Note that, while the vector itself is on the stack, the objects it manages are not. The memory management details are handled within the member functions of vector, which is how it should be. When you do `stack_nodes.push_back(Node(i));`, the `Node` object is copied to the memory that is managed by the vector object, on the heap. – Benjamin Lindley Jan 15 '15 at 03:30
  • 1
    *"trying to create an application where speed is absolutely critical"* - just try to write it elegantly, that's enough of a challenge for a beginning programmer. Then worry about speed *if* you need to - using a profiler for guidance. Your program might surprise you by already being much faster than you need, or might be so much slower that better allocation won't save it - at least you'll know where you stand. – Tony Delroy Jan 15 '15 at 03:36
  • To everyone who just responded: If Benjamin Lindley is correct, my question isn't answered, at least not ideally. If pushing newly-stack-allocated objects to a vector removes the object from the stack and places a copy of it in the heap, then why not just dynamically allocate? –  Jan 15 '15 at 03:36
  • Because then you have to handle the deallocation yourself, which is messy and error prone. – Benjamin Lindley Jan 15 '15 at 03:37
  • "to a vector removes the object from the stack and places a copy of it in the heap" - it's unspecified if the `Node(i)` temporary ever exists on the stack... all you know for sure is that the value is either directly- or copy-constructed in the vector's dynamically allocated (heap) memory. *"then why not just dynamically allocate"* - the `vector<>` object likely holds pointers to the "begin", "end" and "begin+capacity()" addresses and is itself of fixed size and therefore easily handled on the stack... memory needs for elements can vary and is therefore best done dynamically. – Tony Delroy Jan 15 '15 at 03:42
  • Sure, but my question remains: can you instantiate objects within nested scope situations and keep them on the stack? Thank you to Ben for the reply, but looking for confirmation from someone else? EDIT: just saw Tony's answer. What about arrays? –  Jan 15 '15 at 03:43
  • "can you instantiate objects within nested scope situations and keep them on the stack [after that scope has exited]?" - only using `alloca()`, which is fiddly and error prone. Regarding arrays... the problem there is that you may have to guess at a maximum size. Too small and your program dies on larger input, even though the system would be quite willing to give your program more memory to use; too many overly generous arrays and you run out of stack memory. Dynamic allocation handles this better, as well as decoupling allocation from function scopes and call lifetime. – Tony Delroy Jan 15 '15 at 03:46

2 Answers2

1

can't I just instantiate all of my objects on the stack within main?

If you can account for all the objects you'll need, yes.

Heck, COBOL takes that approach as a given. "Here is every variable you will ever need..."

Can I continue to implement this on a somewhat large-scale problem?

With infinite memory, yes. Always.

With finite memory, you may want to manage object lifetimes, and only demand the memory that you actually need at any time.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
1

You can certainly do this for some programs under some circumstances. Just for example, back in the depths of time, Fortran was defined so all the data used by a program could be allocated statically (and it pretty routinely was).

At the same time, it is quite limiting and problematic. Just for a few examples, it rules out (almost) all recursion, which can be really handy for working with some types of recursive data structures (e.g., trees).

It also means that all your variables become essentially globals, so (for example) any code in the program can read and/or write almost any variable in the program. Experience with languages like Fortran and (early versions of) BASIC that used this model indicates that it requires substantial discipline to develop what's currently seen as a small- to medium-sized program, and and developing what's now typically seen as a large system is probably next to impossible. Dependencies between different parts of the code become so complex so quickly that it becomes nearly impossible to determine what's used where, what parts depend upon what others, etc.

I doubt this can be justified in practice. The overhead of allocating stack space starts out so minuscule that eliminating it simply won't improve speed by any noticeable degree. In fact, it may easily do exactly the opposite. Pre-allocating your variables means that each will (pretty much of necessity) live in a unique part of memory. A relatively large percentage of them will be to parts of memory that aren't currently in the cache at a given time, so you'll end up with poor locality of reference leading to poor cache usage.

Allocating local data when you enter a function means that most of your variables live at or close to the top of the stack. Since you're using the memory near the top of the stack almost constantly, that memory stays in the cache most of the time, so nearly all your memory accesses hit the cache.

The time taken for allocations is typically (well) under 1%, but the penalty for accessing main memory instead of the cache is typically at least 10x, and often much higher (20-50x is pretty common). Your mileage will vary depending on data access patterns, but you have a huge potential for a large loss, and (at best) only a small chance of a tiny gain.

Summary: this is a lousy idea. It's much more likely to do a lot of harm than even a tiny bit of good.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thank you Jerry and all others. Everyone had a great response, but I suppose I was looking more if I can allocate to stack is not only possible, but is it a good idea. –  Jan 15 '15 at 03:54