简体   繁体   中英

Why not always instantiate objects on the stack? C++

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?

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.

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 (eg, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM