返回元素比通过引用发送它们并在那里修改要慢吗?

时间:2013-11-22 00:57:56

标签: c++ optimization gcc compiler-construction clang

假设我有一个产生大结构的函数(在本例中是一个巨大的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 ++编写一个编译器,我必须决定我走哪条路;如果我像第一个例子那样编译它或像最后一个例子那样编译它。第一个是微不足道的;最后一个需要一些棘手的编码,但如果速度要快得多,那就值得。

3 个答案:

答案 0 :(得分:1)

按值返回除了最简单的对象之外的所有对象将在99%的时间内更慢。如果向量的长度是无限的,构建整个std::vector<int>的副本的工作量将是巨大的。此外,这是一个潜在的下溢你的堆栈的好方法,如果你的向量最终有1,000,000个元素。在您的第一个示例中,每次通过循环时,image向量也将被复制构造和销毁。您始终可以使用-pg选项编译代码以打开gprof数据并检查结果。

答案 1 :(得分:1)

  • 编译器可以帮助复制省略,但这不是主要问题。您还可以通过内联该函数显式地消除该副本(您可以阅读有关rvalue引用并移动语义以获取其他信息)
  • 编译器可能无法解决实际问题。尽管一次只存在一个向量实例,但总是存在在构造和销毁时正确分配和释放该临时向量的堆内存的开销。然后,它的执行方式将完全取决于标准库的底层分配器实现(std :: cllocator,new,malloc(),...)。分配器可以是智能的并保留该内存以便快速重用,但是,它可能不是(除了事实之外,您可以用自定义的智能分配器替换向量的分配器)。此外,它还取决于分配的内存大小,可用的物理内存和操作系统。大块(相对于总内存)将提前返回。 Linux可以做过度提交(提供比实际可用内存更多的内存)。但是由于矢量实现或渲染器默认情况下分别初始化(使用)所有内存,所以在这里没用。

- &GT;去2。

答案 2 :(得分:1)

最大的问题不是内存分配,而是复制返回时发生的整个矢量。所以第二种选择要好得多。在你的第二个例子中,你也在重复使用相同的向量,它不会为每次迭代分配内存(除非你在某个时候做image.swap(smth))。