如果我有一个返回一个对象的函数,但调用者从不使用这个返回值,那么编译器会优化掉副本吗? (可能总是/有时/从不回答。)
小学的例子:
ReturnValue MyClass::FunctionThatAltersMembersAndNeverFails()
{
//Do stuff to members of MyClass that never fails
return successfulResultObject;
}
void MyClass::DoWork()
{
// Do some stuff
FunctionThatAltersMembersAndNeverFails();
// Do more stuff
}
在这种情况下,ReturnValue
对象是否会被复制?它甚至构建了吗? (我知道这可能取决于编译器,但让我们将讨论范围缩小到流行的现代版本。)
编辑:让我们稍微简化一下,因为在一般情况下似乎没有达成共识。如果ReturnValue
是int,我们返回0而不是successfulResultObject
答案 0 :(得分:3)
如果ReturnValue类有一个非平凡的复制构造函数,编译器不能删除对复制构造函数的调用 - 它是由调用它的语言强制执行的。
如果复制构造函数是内联的,则编译器可能能够内联调用,这反过来可能会导致消除大部分代码(也取决于FunctionThatAltersMembersAndNeverFails是否为内联函数)。
答案 1 :(得分:1)
如果优化级别使它们内联代码,它们很可能会出现。如果没有,他们将不得不生成相同代码的两个不同的翻译,以使其工作,这可能会打开许多边缘案例问题。
答案 2 :(得分:1)
链接器可以处理这类事情,即使原始调用者和被调用者位于不同的编译单元中。
如果您有充分的理由担心专用于方法调用的CPU负载(过早优化是万恶之源),您可以考虑使用许多内联选项,包括(喘气!)一个宏
你真的需要在这个级别进行优化吗?
答案 3 :(得分:1)
如果返回值为int并且您返回0(如编辑后的问题中所示),则此可能会被优化掉。
您必须查看基础程序集。如果函数没有内联,那么底层程序集将执行mov eax,0(或xor eax,eax)将eax(通常用于整数返回值)设置为0.如果函数内联,这肯定会得到优化了。
但是,如果您担心返回大于32位的对象时会发生什么,那么这个senario并不太有用。你需要参考未来问题的答案,这些问题描绘了一幅非常好的图片:如果所有内容都被内联,那么大部分都会被优化掉。如果它没有内联,则必须调用函数,即使它们没有真正做任何事情,并且包括对象的构造函数(因为编译器不知道构造函数是修改了全局变量还是做了别的奇怪的事情)
答案 4 :(得分:0)
我怀疑大多数编译器是否可以在不同的编译对象(即不同的文件)中执行此操作。也许如果他们都在同一个文件中,他们可以。
答案 5 :(得分:0)
窥视孔优化器很有可能会抓住这个。许多(大多数?)编译器实现了一个,所以答案可能是“是”。
正如其他人所指出的那样,这在AST改写水平上并不是一个微不足道的问题。
窥孔优化器在与汇编语言等效的级别(但在生成实际机器代码之前)处理代码表示。有可能注意到返回值加载到寄存器中,然后是没有中间读取的覆盖,只需删除负载即可。这是根据具体情况完成的。
答案 6 :(得分:0)