6

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

基本示例:

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呢?

4

7 回答 7

3

如果 ReturnValue 类具有重要的复制构造函数,则编译器不得消除对复制构造函数的调用——它是由调用它的语言所要求的。

如果复制构造函数是内联的,编译器可能能够内联调用,这反过来可能会导致删除其大部分代码(也取决于 FunctionThatAltersMembersAndNeverFails 是否内联)。

于 2008-11-07T18:12:20.800 回答
1

如果优化级别导致他们内联代码,他们很可能会这样做。如果不是这样,他们将不得不为相同的代码生成两种不同的翻译才能使其正常工作,这可能会引发很多极端情况问题。

于 2008-11-07T18:02:27.683 回答
1

链接器可以处理这类事情,即使原始调用者和被调用者位于不同的编译单元中。

如果您有充分的理由担心专用于方法调用的 CPU 负载(过早的优化是万恶之源),您可能会考虑许多可用的内联选项,包括(喘气!)宏。

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

于 2008-11-07T18:04:30.720 回答
1

如果返回值是一个 int 并且您返回 0(如已编辑的问题中所示),那么这可能会被优化掉。

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

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

于 2008-11-11T01:47:57.803 回答
0

如果大多数编译器位于不同的编译对象(即不同的文件)中,我怀疑它们是否可以做到这一点。也许如果他们都在同一个文件中,他们可以。

于 2008-11-07T17:59:01.200 回答
0

窥视孔优化器很有可能会抓住这一点。许多(大多数?)编译器都实现了一个,所以答案可能是“是”。

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


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

于 2008-11-07T18:17:46.217 回答
0

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

https://gcc.godbolt.org/z/v5WGPr

在此处输入图像描述

于 2020-10-19T23:07:42.363 回答