为什么不总是在堆栈上实例化对象? C++

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

剧透仅包含背景和上下文

! 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.


我正在尝试创建一个速度绝对关键的应用程序,我不能只在 main 中实例化堆栈上的所有对象,然后简单地将嵌套范围内的每个实例化保存到外部容器吗?

我自己使用包含 属性 "id" 的简单节点 class 对此进行了测试。 我实例化了堆栈上的节点,将它们放在一个向量中,这样它们就不会被释放,然后(只是为了检查)我将新项目分配到堆栈,然后检查以确保先前分配的数据仍然存在。我可以继续在一个有点大的问题上实施这个吗?

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;
}

编辑: 请参阅下面的评论。当您 return 从其创建范围中分配的堆栈对象时,将创建该对象的副本。该副本也在堆栈上吗?如果我将该复制的对象分配给在 main 范围内声明的向量,该对象是否仍在堆栈中?

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

如果你能说明你需要的所有对象,是的

哎呀,COBOL 将这种方法视为既定方法。 "Here is every variable you will ever need..."

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

无限记忆,是的。总是。

在内存有限的情况下,您可能希望管理对象的生命周期,并且在任何时候只需要您实际需要的内存。

在某些情况下,您当然可以对某些程序执行此操作。举个例子,在很久很久以前,Fortran 被定义为程序 所使用的所有数据都可以 静态分配(而且通常是这样)。

同时,它的局限性和问题性也很大。仅举几个例子,它排除了(几乎)所有递归,这对于处理某些类型的递归数据结构(例如树)非常方便。

这也意味着您的所有变量本质上都变成了全局变量,因此(例如)程序中的任何代码都可以读取 and/or 几乎可以写入程序中的任何变量。使用此模型的 Fortran 和(早期版本)BASIC 等语言的经验表明,开发目前被视为中小型程序的程序需要大量的纪律,而开发现在通常被视为大型系统的程序可能是几乎不可能。代码不同部分之间的依赖关系变得如此复杂,以至于几乎不可能确定在哪里使用了什么,哪些部分依赖于其他部分,等等。

我怀疑这在实践中是否合理。分配堆栈 space 的开销开始 所以 微不足道,消除它根本不会以任何明显的程度提高速度。事实上,它很可能恰恰相反。预先分配你的变量意味着每个变量都(非常必要)存在于内存的一个独特部分。它们中的很大一部分将用于在给定时间当前不在缓存中的内存部分,因此您最终会遇到引用位置不佳导致缓存使用率低下的情况。

在您输入函数时分配本地数据意味着您的大部分变量位于或接近堆栈顶部。由于您几乎一直在使用靠近堆栈顶部的内存,因此该内存大部分时间都保留在缓存中,因此几乎所有内存访问都会命中缓存。

分配所花费的时间通常(很好)低于 1%,但访问主内存而不是缓存的代价通常至少为 10 倍,而且通常更高(20-50 倍很常见)。您的里程数会因数据访问模式而异,但您有可能遭受巨大损失,并且(充其量)获得微小收益的可能性很小。

总结:这是个糟糕的主意。它很多造成很多伤害的可能性比哪怕是一点点好处都大。