C++ c++;编译器优化掉未使用的返回值?

C++ c++;编译器优化掉未使用的返回值?,c++,visual-c++,gcc,compiler-construction,return,C++,Visual C++,Gcc,Compiler Construction,Return,如果我有一个返回对象的函数,但调用方从未使用这个返回值,编译器会优化掉副本吗?(可能是始终/有时/从不回答。) 基本示例: ReturnValue MyClass::FunctionThatAltersMembersAndNeverFails() { //Do stuff to members of MyClass that never fails return successfulResultObject; } void MyClass::DoWork() { //

如果我有一个返回对象的函数,但调用方从未使用这个返回值,编译器会优化掉副本吗?(可能是始终/有时/从不回答。)

基本示例:

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

我怀疑大多数编译器在不同的编译对象(即不同的文件)中都能这样做。如果它们都在同一个文件中,它们可能会这样做。

如果优化级别导致它们内联代码,它们很可能会这样做。否则,他们将不得不对同一代码生成两种不同的翻译以使其正常工作,这可能会引发许多边缘问题。

链接器可以处理此类问题,即使原始调用方和被调用方位于不同的编译单元中

如果你有一个很好的理由关注一个方法调用的CPU负载(过早优化是所有邪恶的根源),你可能会考虑到许多可用的内联选项,包括(GASP!)宏。


您真的需要在这个级别进行优化吗?

如果ReturnValue类有一个非常重要的复制构造函数,编译器不能取消对复制构造函数的调用—它是由调用它的语言强制执行的


如果复制构造函数是内联的,则编译器可能能够内联调用,这反过来可能会导致删除其大部分代码(还取决于更改成员和无故障的函数是否是内联的)。

窥视孔优化器很有可能会捕捉到这一点。许多(大多数?)编译器都实现了一个,因此答案可能是“是”

正如其他人所指出的,在AST重写级别,这不是一个微不足道的问题



窥视孔优化器在相当于汇编语言的级别(但在生成实际机器代码之前)处理代码的表示。有可能会注意到将返回值加载到寄存器中,然后进行覆盖(不进行中间读取),然后删除加载。这是根据具体情况进行的。

如果返回值为int,并且您返回0(如编辑的问题中所示),则这可能会得到优化

您必须查看底层程序集。如果函数未内联,则底层程序集将执行mov eax,0(或xor eax,eax)以将eax(通常用于整数返回值)设置为0。如果函数是内联的,这肯定会得到优化


但是,如果您担心返回大于32位的对象时会发生什么,那么这个senario就没有太大用处。您需要参考unedit问题的答案,这描绘了一幅非常好的画面:如果所有内容都是内联的,那么大部分内容都将被优化。如果它不是内联的,那么即使函数实际上没有做任何事情,也必须调用函数,这包括对象的构造函数(因为编译器不知道构造函数是否修改了全局变量或做了其他奇怪的事情)。

刚刚在编译器资源管理器上尝试了这个示例,在-O3,当不使用返回值时,不会生成
mov


同意。如果返回值从未在任何调用中使用过,启用“整个程序优化”也可能实现。@Drew,“整个程序优化”是vc++的东西吗,因为我无法想象在Linux/Unix环境中它是可能的。例如,有传闻说这方面的努力:@Paul,这是可能的,但是您基本上告诉GCC编译所有源文件,并给它-fwhole程序标志。它可以很容易地使用1.5 GB的RAM和更多的内存,但事实并非如此。在临时对象的特定情况下,编译器有明确的权限在其目的地直接构造对象,而不是复制对象(参见ISO 14882§12.2)。如果中间对象有一个名称,那么您是正确的。在给定的示例中,它怎么能不调用复制构造函数(假设successfulResultObject的类型已经是ReturnValue)?“直接复制”,在这种特定情况下,仍然涉及复制构造函数。“编译器不得取消对复制构造函数的调用”-此信息似乎错误,否则将不可能,是吗?链接器无法进行任何类似的优化。被调用的函数无法知道结果是否正在使用,因此必须生成它。只有编译器有足够的知识来接近优化,只有当所有东西都是内联的时候才会发生。我想他可能在谈论像微软这样的链接器,我认为它需要所有对象的中间表示,并执行另一个编译步骤,以便进行模块间优化。@ZanLynx不再只是MS,GCC有非常完善的链接时间优化,打开它意味着编译器可以看到的任何内容现在都是可见的(以中间格式流式传输)连接到链接器,可以内联或以其他方式跨翻译单元边界进行优化,通常会产生显著的效果。我认为这同样适用于LLVM/Clang和任何其他跟上竞争对手的现代编译器