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

C++ 返回小结构的虚函数-返回值与输出参数?,c++,C++,我在热点代码中有一个虚拟函数,因此需要返回一个结构。我有两个选择: virtual Vec4 generateVec() const = 0; // return value virtual void generateVec(Vec4& output) const = 0; // output parameter 我的问题是,这些功能的性能通常有什么不同吗?我假设第二个更快,因为它不涉及在堆栈上复制数据。然而,第一个通常更方便使用。如果第一个仍然稍微慢一点,这是可以测量的吗?我是不是

我在热点代码中有一个虚拟函数,因此需要返回一个结构。我有两个选择:

virtual Vec4 generateVec() const = 0; // return value

virtual void generateVec(Vec4& output) const = 0; // output parameter
我的问题是,这些功能的性能通常有什么不同吗?我假设第二个更快,因为它不涉及在堆栈上复制数据。然而,第一个通常更方便使用。如果第一个仍然稍微慢一点,这是可以测量的吗?我是不是太痴迷了:)


让我强调一下,这个函数每秒调用数百万次,但结构Vec4的大小很小,只有16个字节。

每秒调用数百万次的代码意味着您确实需要优化速度

根据衍生的generateVec的主体有多复杂,两者之间的差异可能是不明显的,也可能是巨大的


最好的办法是同时尝试这两种方法,并分析一下您是否需要担心优化代码的这一特定方面。

如前所述,尝试一下它们-但您很可能会发现
Vec4 generateVec()
实际上更快。而
void generateVec(Vec4&output)
可能会导致对
output
参数进行不必要的初始化


有什么方法可以避免使函数虚拟化?如果你以每秒数百万次的速度呼叫它,那么额外的间接级别是值得一看的。

感觉有点无聊,所以我提出了以下建议:

#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;
}   
#包括
#包括
#包括
使用名称空间std;
结构A{
int n[4];
(){
n[0]=n[1]=n[2]=n[3]=rand();
}
};
A f1(){
返回A();
}
A f2(A&A){
a=a();
}
const unsigned long BIG=100000000;
int main(){
无符号整数和=0;
A A;
时钟t=时钟();
for(无符号整数i=0;icout第一个解决方案可能更快

一篇很好的文章:


出于好奇,我编写了两个类似的函数(使用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,__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    $2, -8(%ebp)
        movl    $0, -4(%ebp)
        movl    8(%ebp), %ecx
        movl    -8(%ebp), %eax
        movl    -4(%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编译。

与所有性能问题一样,答案是同时实现和计时。此外,如果性能是问题,您可以尝试更改代码,以避免使用虚拟方法。有趣的是,我不希望第一个方法实际上更快。不幸的是,我无法摆脱虚拟函数,他说这是一个问题。如果不是虚拟的,我可以将其内联。复制操作真的会在虚拟调用中被忽略吗?现在,编写一个不能内联的版本,并且不是(n)rvo的候选版本,希望你能有一个很好的例子说明为什么通用优化建议不起作用。