C++ 做C++;编译器将pass-by-const参考POD参数优化为pass-by-copy?
考虑以下几点:C++ 做C++;编译器将pass-by-const参考POD参数优化为pass-by-copy?,c++,optimization,C++,Optimization,考虑以下几点: struct Point {double x; double y;}; double complexComputation(const& Point p1, const Point& p2) { // p1 and p2 used frequently in computations } 编译器是否优化了“按引用传递”到“按副本传递”以防止频繁取消引用?换句话说,将complexComputation转换为: double complexComputa
struct Point {double x; double y;};
double complexComputation(const& Point p1, const Point& p2)
{
// p1 and p2 used frequently in computations
}
编译器是否优化了“按引用传递”到“按副本传递”以防止频繁取消引用?换句话说,将complexComputation
转换为:
double complexComputation(const& Point p1, const Point& p2)
{
double x1 = p1.x; double x2 = p2.x;
double y1 = p1.y; double y2 = p2.y;
// x1, x2, y1, y2 stored in registers and used frequently in computations
}
因为Point是一个POD,所以在打电话的人背后复制不会有任何副作用,对吗
如果是这样的话,那么我总是可以通过const引用传递POD对象,不管它有多小,并且不必担心最佳传递语义。对吧?
编辑:
我对GCC编译器特别感兴趣。我想我可能需要编写一些测试代码并查看ASM。我不能代表每个编译器,但一般的答案是否定的。它不会进行优化 <>请参阅C++中如何将CuxtoCase> const 不影响某些人可能会想到的优化。 < P>如果需要,编译器可以将点成员变量绝对提升到寄存器中。但是,这与编译器将函数调用本身转换为传递值不同 您应该检查生成的程序集,以查看正在进行哪些优化 而FWIW,我使用的一般规则是,在可能的情况下,通过值传递所有的primative类型,通过const引用传递所有的class/udt(pod或not),并让编译器选择最好的方法。我们不必担心编译器正在做什么的细节,它比我们聪明得多。有两个问题 首先,编译器不会将pass-by-ref转换为pass-by-value,特别是当
complexComputation
不是static
(即可由外部对象使用)时
原因是API兼容性。对于CPU来说,没有所谓的“参考”。编译器将把引用转换为指针。参数通过堆栈或寄存器传递,因此调用complexComputation
的代码可能会被调用为(假设double
的长度暂时为4):
只有8个字节被推送到堆栈上
另一方面,passbycopy将把整个结构推到堆栈上,因此汇编代码看起来像
push x1 ; push a copy of p1.x onto the stack
push y1 ; push a copy of p1.y onto the stack
push x2 ; push a copy of p2.x onto the stack
push y2 ; push a copy of p2.y onto the stack
call complexComputation
请注意,这次16个字节被推送到堆栈上,内容是数字,而不是指针。如果complexComputation
更改其参数传递语义,输入将变成垃圾,您的程序可能会崩溃
另一方面,优化
double complexComputation(const Point& p1, const Point& p2) {
double x1 = p1.x; double x2 = p2.x;
double y1 = p1.y; double y2 = p2.y;
// x1, x2, y1, y2 stored in registers and used frequently in computations
}
这很容易做到,因为编译器可以识别经常使用的变量,并且
将它们存储到保留寄存器中(例如ARM体系结构中的r4~r13,以及许多sXX/dXX寄存器),以便更快地访问
毕竟,如果你想知道编译器是否做了一些事情,你可以随时反汇编生成的对象并进行比较。我试图搜索这个问题,但我不断地找到关于通过值传递、通过引用传递等abc的答案。如果已经讨论过,我很抱歉。通常,相反的方法可能是更好的方法(). 传递值,并让编译器在需要时将其转换为传递引用。除非基准测试/评测告诉我们,否则我同意不要担心。但我只是好奇编译器是否真的可以进行这种类型的优化。
double complexComputation(const Point& p1, const Point& p2) {
double x1 = p1.x; double x2 = p2.x;
double y1 = p1.y; double y2 = p2.y;
// x1, x2, y1, y2 stored in registers and used frequently in computations
}