调用堆栈上大量对象的构造函数

Posted

技术标签:

【中文标题】调用堆栈上大量对象的构造函数【英文标题】:Calling the constructor of a large array of objects on a stack 【发布时间】:2011-02-04 01:57:09 【问题描述】:

我正在修改一些 C++ 源代码,我注意到作者确实不遗余力地分配堆栈上的所有内容。最有可能获得解除分配的好处(是否还有任何性能好处??)。

我想保持相同的一致性,但我需要创建大量对象,例如:

Object os[1000] = Object(arg), Object(arg), ....;

不会剪掉它。搜索它似乎是一种解决方法:

vector<Object> os(1000, Object(arg));

这仍然在堆上分配,但像堆栈一样释放(来自我在其他帖子中读到的内容)。我只是想知道还有其他选择,因为这似乎是一个语法问题。也许聪明的#define 人都知道。

【问题讨论】:

我的意思是这主要是在开玩笑,但也有一定的道理......有一个选择:学习如何使用指针和引用并进行设计,这样内存管理就不是问题了。 性能优势:堆栈分配总是 O(1);堆分配是不确定的。 @Mehrdad:如果您使用的是具有无限堆栈的理想计算机,它们总是 O(1)...。在现实世界中,您最终分配的内存将超过当前的堆栈限制,而操作系统将不得不为您分配更多内存……或者在最坏的情况下,您将用完可用的堆栈空间,然后您的进程就结束了。跨度> @Matti:好吧,我承认我没有想到 Stack Overflow(……是的……)。但老实说,堆栈扩展是一次性事件,只要您一次分配的空间不超过 2-4 KB(大约为 PAGE_SIZE),它们显然比堆分配要快。跨度> @Mehrdad:他试图分配一千个不知道大小的对象。 【参考方案1】:

堆栈不应用于大内存块。您只需支付更高的堆分配价格,以换取访问更多内存的好处。另一种选择是声明一个具有静态存储持续时间的数组,但这有其他缺点(不可重入,非线程安全)。一切都是权衡。

无论如何,在分配复杂对象时,调用 1000 个构造函数的成本将使分配器所花费的时间相形见绌。只需使用std::vector,除非您的分析器数据显示存在性能问题。

【讨论】:

【参考方案2】:

是的,还有其他选择。你可以使用alloca 之类的东西。这将使您获得堆栈分配和自动释放,但不会自动构造或销毁。您需要使用放置 new 和显式调用析构函数。

是的,可能有性能优势,但你也乞求破坏堆栈,并且这种模式不像 vector 解决方案那样异常安全(也就是说,如果你分配的对象有一个非-琐碎的析构函数)。

【讨论】:

【参考方案3】:

一般来说,在堆栈上分配大量数据是一个坏主意。大多数操作系统上的堆栈是一个暂存空间,并且大小相当有限。为对象分配大量堆栈空间会很快消耗所有可用的堆栈空间,当某些东西试图在堆栈上再分配一个东西(例如,函数调用的返回地址)时,会导致段错误或其他异常。

至于其他选项,您有几个......您已经注意到 std::vector 以及 boost::array 都是这样的例子。

【讨论】:

【参考方案4】:

这应该可以工作:

Object os[1000];
os[0] = Object(args);
std::copy(os, os + 999, os + 1);

这会创建数组,初始化一个对象,然后循环遍历,用最后一个元素初始化每个元素。

当然,您可能不应该使用它。即使它有效,即使Object os[1000] 不会给您带来问题,这似乎也是个坏主意。

【讨论】:

以上是关于调用堆栈上大量对象的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

1--面试总结-js深入理解,对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This

在堆栈上声明对象的两种方式之间的区别

在非构造的“对象”上调用非虚拟成员函数是不是定义明确? [复制]

生成一个派生类对象时,调用基类和派生类构造函数按啥次序

使用受保护构造函数和复制构造函数创建 C++ 非堆工厂对象

对象指针