直到今天,我一直认为,如果结构足够大以至于后者会更快,那么不错的编译器会自动将结构传递值转换为传递引用。据我所知,这似乎是最明智的选择。但是,为了满足我对这种情况是否真的发生的好奇心,我在C++和D中创建了一个简单的测试用例,并查看了GCC和Digital Mars D的输出。两者都坚持在传递所有值时传递32字节结构有问题的函数所做的是将成员加起来并返回值,而无需传入传入的结构。C++版本如下。
#include "iostream.h"
struct S {
int i, j, k, l, m, n, o, p;
};
int foo(S s) {
return s.i + s.j + s.k + s.l + s.m + s.n + s.o + s.p;
}
int main() {
S s;
int bar = foo(s);
cout << bar;
}
我的问题是,为什么编译器不会优化这种类似的东西以传递引用,而不是将所有这些
int
实际压入堆栈?注意:使用的编译器开关:GCC -O2(-O3内联foo()。),DMD -O -inline -release。
编辑:显然,在一般情况下,按值传递与按引用传递的语义将是不同的,例如,如果涉及复制构造函数,或者在被调用方中修改了原始结构,则该语义是相同的。但是,在许多现实情况下,语义在可观察到的行为方面都是相同的。这些是我要问的情况。
最佳答案
不要忘记,在C / C++中,编译器仅需要能够基于函数声明来编译对函数的调用。
由于调用者可能仅使用该信息,因此编译器无法编译该函数以利用您正在谈论的优化。调用者不知道该函数不会修改任何内容,因此它不能被ref传递。由于某些调用者可能由于缺少详细信息而按值传递,因此必须在假定传递值的情况下编译函数,并且每个人都需要按值传递。
请注意,即使您将参数标记为“const
”,编译器仍然无法执行优化,因为该函数可能在说谎并舍弃了constness(只要传入对象,就可以允许并定义良好)实际上不是const)。
我认为对于静态函数(或匿名命名空间中的函数),编译器可能会进行您正在讨论的优化,因为该函数没有外部链接。只要函数的地址没有传递给其他例程或存储在指针中,就不应从其他代码中调用它。在这种情况下,编译器可以完全了解所有调用者,因此我想它可以进行优化。
我不确定是否可以这样做(实际上,如果可以这样做,我会感到很惊讶,因为它可能无法经常应用)。
当然,作为程序员(使用C++时),您可以通过使用const&
参数强制编译器执行此优化。我知道您在问为什么编译器无法自动执行此操作,但是我想这是下一个最好的选择。
关于performance - 为什么通过引用传递结构不是常见的优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/552134/