假设我有一个函数可以生成一个大结构(在本例中是一个巨大的 std::vector),以及一个重复调用它的循环:
std::vector<int> render(int w, int h, int time){
std::vector<int> result;
/* heavyweight drawing procedures */
return result;
};
while(loop){
std::vector<int> image = render(800,600,time);
/*send image to graphics card*/
/*...*/
};
我的问题是:在这种情况下,GCC/Clang 是否足够聪明,可以避免在每次迭代时为巨大的 800x600x4 数组分配内存?换句话说,这段代码的执行是否类似于:
void render(int w, int h, int time, std::vector<int>& image){ /*...*/ }
std::vector<int> image;
while(loop){
render(800,600,time,image);
/*...*/
}
为什么问这个问题:我正在制作一个从语言到 C++ 的编译器,我必须决定走哪条路;如果我像第一个例子或最后一个例子一样编译它。第一个是微不足道的;最后一个需要一些棘手的编码,但如果它速度相当快,那么可能是值得的。
按值返回除最琐碎的对象之外的所有对象在 99% 的情况下都会变慢。 如果向量的长度是无限的,那么构建整个
std::vector<int>
的副本的工作量将是巨大的。 另外,如果你的向量最终有 1,000,000 个元素,那么这也是一个潜在的堆栈下溢的好方法。 在第一个示例中,每次通过循环都会复制构造和破坏 image
向量。 您始终可以使用 -pg 选项编译代码以打开 gprof 数据并检查结果。
最大的问题不是内存分配,而是返回时发生的整个向量的复制。所以第二种选择要好得多。在第二个示例中,您还重复使用相同的向量,这不会为每次迭代分配内存(除非您在某个时刻执行 image.swap(smth) )。
--> 去 2。