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

标签 c++ memory-management scope stack

剧透仅包含背景和上下文

! 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”的简单 Node 类对此进行了测试。 我实例化了堆栈上的节点,将它们放在一个 vector 中,这样它们就不会被释放,然后(只是为了检查)我将新项目分配到堆栈,然后检查以确保之前分配的数据仍然存在。我可以继续在一个有点大的问题上实现这个吗?

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

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

最佳答案

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

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

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

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

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

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

总结:这是一个糟糕的想法。 更有可能造成很多伤害,而不是一点点好处。

关于c++ - 为什么不总是在堆栈上实例化对象? C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27956253/

相关文章:

c++ - 每次继承时都需要boost::serialization::base_object吗?

iphone - 使用 Objective C 监控有关 iPhone 运行进程的信息

asp.net-mvc - Ninject 单例范围

jsf - 如何从 View 范围的 JSF bean 中获取请求参数?

c++ - 在 vector 中搜索其第一个参数的所有实例,然后将它们返回到 vector 中

c++ - C++98 中的异构容器查找

c++ - 最小化单应矩阵中的误差

c# - List<struct> 与 List<class> 的性能

C++ 堆碎片分配错误?

PHP在类中使用全局空间的变量