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的候选版本,希望你能有一个很好的例子说明为什么通用优化建议不起作用。