返回较小结构的虚函数-返回值与输出参数?

问题描述

| 我在热点代码中有一个函数,因此需要返回一个结构。我有两个选择:
virtual Vec4 generateVec() const = 0; // return value

virtual void generateVec(Vec4& output) const = 0; // output parameter
我的问题是,这些功能性能一般是否有差异?我认为第二个更快,因为它不涉及在堆栈上复制数据。但是,第一个通常更方便使用。如果第一个仍然稍微慢一点,这是否可以测量?我也迷恋吗:) 让我强调一下,此函数每秒将被调用数百万次,而且结构Vec4的大小很小-16个字节。     

解决方法

        如前所述,尝试一下-但是您很可能会发现ѭ1实际上更快。返回值优化将避免复制操作,而
void generateVec(Vec4& output)
可能会不必要地初始化
output
参数。 有什么方法可以避免将函数虚拟化?如果您每秒调用数百万次,则值得研究一下额外的间接级别。     ,        每秒调用数百万次的代码意味着您确实确实需要优化速度。 根据派生的generateVec主体的复杂程度,两者之间的差异可能不明显,也可能很大。 最好的选择是同时尝试它们和配置文件,以查看是否需要担心优化代码的这一特定方面。     ,        感觉有点无聊,所以我想到了这个:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

struct A {
    int n[4];
    A() {
        n[0] = n[1] = n[2] = n[3] = rand();
    }
};

A f1() {
    return A();
}

A f2( A & a ) {
    a = A();
}

const unsigned long BIG = 100000000;

int main() {
    unsigned int sum =  0;
    A a;
    clock_t t = clock();
    for ( unsigned int i = 0; i < BIG; i++ ) {
        a = f1();
        sum += a.n[0];
    }
    cout << clock() - t << endl;
    t = clock();
    for ( unsigned int i = 0; i < BIG; i++ ) {
        f2( a );
        sum += a.n[0];
    }
    cout << clock() - t << endl;
    return sum & 1;
}   
-O2优化的结果是没有显着差异。     ,        第一种解决方案有可能更快。 一篇非常好的文章: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/     ,        出于好奇,我编写了2个类似的函数(使用8字节数据类型)来检查其汇编代码。
long long int ret_val()
{
    long long int tmp(1);
    return tmp;
}

// ret_val() assembly
.globl _Z7ret_valv
        .type   _Z7ret_valv,@function
_Z7ret_valv:
.LFB0:
        .cfi_startproc
        .cfi_personality 0x0,__gxx_personality_v0
        pushl   %ebp
        .cfi_def_cfa_offset 8
        movl    %esp,%ebp
        .cfi_offset 5,-8
        .cfi_def_cfa_register 5
        subl    $16,%esp
        movl    $1,-8(%ebp)
        movl    $0,-4(%ebp)
        movl    -8(%ebp),%eax
        movl    -4(%ebp),%edx
        leave
        ret
        .cfi_endproc
令人惊讶的是,下面的按值传递方法还需要一些说明:
void output_val(long long int& value)
{
    long long int tmp(2);
    value = tmp;
}

// output_val() assembly
.globl _Z10output_valRx
        .type   _Z10output_valRx,@function
_Z10output_valRx:
.LFB1:
        .cfi_startproc
        .cfi_personality 0x0,%esp
        movl    $2,-4(%ebp)
        movl    8(%ebp),%ecx
        movl    -8(%ebp),%edx
        movl    %eax,(%ecx)
        movl    %edx,4(%ecx)
        leave
        ret
        .cfi_endproc
这些功能在测试代码中的调用方式为:
 long long val = ret_val();

 long long val2;
 output_val(val2);
由gcc编译。