在不实例化局部变量的情况下将结构传递给函数的效率
Efficiency of passing a struct to a function without instantiating a local variable
我最近了解到我可以通过将结构传递给 C++ 中的函数来执行以下操作:
(很抱歉没有在标题中为这个 "feature" 使用更合适的名称,请随时纠正我)
#include <iostream>
typedef struct mystruct{
int data1;
int data2;
} MYSTRUCT;
void myfunction( MYSTRUCT _struct ){
std::cout << _struct.data1 << _struct.data2;
}
int main(){
//This is what I recently learned
myfunction( MYSTRUCT{2,3} );
return 0;
}
这让我想知道这是否比实例化本地 MYSTRUCT
成本更低
并将其按值传递给函数?或者它只是一种方便的方法来做同样的事情,只是在之后立即删除临时变量?
例如添加这一行#define KBIG 10000000
,是这样的:
std::vector<MYSTRUCT> myvector1;
for (long long i = 0; i < KBIG; i++) {
myvector1.push_back(MYSTRUCT{ 1,1 });
}
始终比这更快:
std::vector<MYSTRUCT> myvector2;
for (long long i = 0; i < KBIG; i++) {
MYSTRUCT localstruct = { 1,1 };
myvector2.push_back(localstruct);
}
我尝试对其进行测试,但结果非常不一致,每次都在 9-12 秒左右徘徊。有时第一个会更快,有时则不会。当然,这可能是我测试时所有后台进程的原因。
如果速度有任何问题,请测量复制与采用 const ref(即 const MYSTRUCT& _struct
)。进行测量时,请确保先执行 <1> <2>,然后执行 <2> <1> 以补偿缓存效应。
建议:避免使用_
作为参数的第一个字符,因为一些保留字以它开头;另外,不要大写struct。
如果你想加速你的代码,我建议你通过 const 引用传递结构,如下所示:
void myfunction (const MYSTRUCT& _struct)
{
std::cout << _struct.data1 << _struct.data2;
}
这将比按值传递快得多,因为它不会复制整个结构,而只会传递其地址。
(好的,在这种情况下不会有太大差异,因为你的结构只包含 2 个整数,但如果你有 >1000 字节(例如)那么会有显着差异)
此外,我建议您使用 std::vector<T>::emplace_back
而不是 std::vector<T>::push_back
std::vector<MYSTRUCT> myvector1;
for (long long i = 0; i < KBIG; i++)
{
myvector1.emplace_back (1, 1);
}
emplace_back
将其参数转发给 mystruct
的构造函数,因此编译器不会创建无用的副本。
稍微简化并编译为汇编程序:
extern void emit(int);
typedef struct mystruct{
int data1;
int data2;
} MYSTRUCT;
__attribute__((noinline))
void myfunction( MYSTRUCT _struct ){
emit(_struct.data1);
emit(_struct.data2);
}
int main(){
//This is what I recently learned
myfunction( MYSTRUCT{2,3} );
return 0;
}
使用 -O2 产量:
myfunction(mystruct):
pushq %rbx
movq %rdi, %rbx
call emit(int)
sarq , %rbx
movq %rbx, %rdi
popq %rbx
jmp emit(int)
main:
movabsq 884901890, %rdi
subq , %rsp
call myfunction(mystruct)
xorl %eax, %eax
addq , %rsp
ret
发生了什么事?
编译器意识到整个结构适合一个寄存器并以这种方式按值传递它。
故事的寓意:表达意图。让编译器操心细节。
如果你需要一份,你需要一份。故事结束。
我最近了解到我可以通过将结构传递给 C++ 中的函数来执行以下操作:
(很抱歉没有在标题中为这个 "feature" 使用更合适的名称,请随时纠正我)
#include <iostream>
typedef struct mystruct{
int data1;
int data2;
} MYSTRUCT;
void myfunction( MYSTRUCT _struct ){
std::cout << _struct.data1 << _struct.data2;
}
int main(){
//This is what I recently learned
myfunction( MYSTRUCT{2,3} );
return 0;
}
这让我想知道这是否比实例化本地 MYSTRUCT
成本更低
并将其按值传递给函数?或者它只是一种方便的方法来做同样的事情,只是在之后立即删除临时变量?
例如添加这一行#define KBIG 10000000
,是这样的:
std::vector<MYSTRUCT> myvector1;
for (long long i = 0; i < KBIG; i++) {
myvector1.push_back(MYSTRUCT{ 1,1 });
}
始终比这更快:
std::vector<MYSTRUCT> myvector2;
for (long long i = 0; i < KBIG; i++) {
MYSTRUCT localstruct = { 1,1 };
myvector2.push_back(localstruct);
}
我尝试对其进行测试,但结果非常不一致,每次都在 9-12 秒左右徘徊。有时第一个会更快,有时则不会。当然,这可能是我测试时所有后台进程的原因。
如果速度有任何问题,请测量复制与采用 const ref(即 const MYSTRUCT& _struct
)。进行测量时,请确保先执行 <1> <2>,然后执行 <2> <1> 以补偿缓存效应。
建议:避免使用_
作为参数的第一个字符,因为一些保留字以它开头;另外,不要大写struct。
如果你想加速你的代码,我建议你通过 const 引用传递结构,如下所示:
void myfunction (const MYSTRUCT& _struct)
{
std::cout << _struct.data1 << _struct.data2;
}
这将比按值传递快得多,因为它不会复制整个结构,而只会传递其地址。
(好的,在这种情况下不会有太大差异,因为你的结构只包含 2 个整数,但如果你有 >1000 字节(例如)那么会有显着差异)
此外,我建议您使用 std::vector<T>::emplace_back
而不是 std::vector<T>::push_back
std::vector<MYSTRUCT> myvector1;
for (long long i = 0; i < KBIG; i++)
{
myvector1.emplace_back (1, 1);
}
emplace_back
将其参数转发给 mystruct
的构造函数,因此编译器不会创建无用的副本。
稍微简化并编译为汇编程序:
extern void emit(int);
typedef struct mystruct{
int data1;
int data2;
} MYSTRUCT;
__attribute__((noinline))
void myfunction( MYSTRUCT _struct ){
emit(_struct.data1);
emit(_struct.data2);
}
int main(){
//This is what I recently learned
myfunction( MYSTRUCT{2,3} );
return 0;
}
使用 -O2 产量:
myfunction(mystruct):
pushq %rbx
movq %rdi, %rbx
call emit(int)
sarq , %rbx
movq %rbx, %rdi
popq %rbx
jmp emit(int)
main:
movabsq 884901890, %rdi
subq , %rsp
call myfunction(mystruct)
xorl %eax, %eax
addq , %rsp
ret
发生了什么事?
编译器意识到整个结构适合一个寄存器并以这种方式按值传递它。
故事的寓意:表达意图。让编译器操心细节。
如果你需要一份,你需要一份。故事结束。