C++:编译器能优化传值操作吗?

15

一个常见的编译器优化是所谓的返回值优化。这种优化基本上允许编译器不复制从函数返回的本地变量,而是将其移动。

然而,我在想如果对于按值传递参数到函数中,如果已知函数的返回值将覆盖原始参数,是否也可以做到同样的优化。

以下是一个示例。假设我们有以下函数:

std::vector<Foo> modify(std::vector<Foo> data) {
    /* Do some funny things to data */
    return data;
}

然后,以下是使用此函数的方式:

std::vector<Foo> bigData = /* big data */;
bigData = modify(bigData); // Here copying the data into the function could be omitted

在这种情况下,可以明确确定函数调用的返回值将覆盖传递到函数中的参数。我的问题是,当前编译器是否能够优化此代码,使得传递给函数的参数在传递时不被复制,或者这甚至可能是所谓的返回值优化的一部分。

更新

让我们考虑C++11,我想知道以下理解是否正确:如果通过值传递到函数参数的值是r值,并且参数的类型具有移动构造函数,则将使用移动构造函数而不是复制构造函数。

例如:

std::vector<Foo> bigData = /* big data */;
bigData = modify(std::move(bigData));

如果这个假设是正确的,那么在传递值时就会消除复制操作。从已经给出的答案来看,我提到的优化似乎不常见。看着这个手动方式,我真的不明白为什么,因为它似乎很容易实现。


3
这个问题很难给出确切的答案,但是如果我必须打赌的话:我认为你永远不会获得这种优化,除非该函数被内联。 - Nir Friedman
4
“要明确回答这个问题很困难。”——嗯,其实还是比较容易的,只需要选择你感兴趣的编译器然后查看生成的汇编代码即可。 - UKMonkey
4
@UKMonkey 很容易回答,对于特定的函数、特定的编译器、特定的架构以及特定的标志,我同意。但问题更加普遍,函数体并没有指定,所以我不会说这很“容易”。无论如何,我尽力回答了这个问题。 - Nir Friedman
3个回答

4
很难确定,因为原则上编译器可以优化许多东西,只要它们确信具有相同的行为。然而,在我的经验中,如果没有内联,这种优化不会发生。考虑以下代码:
__attribute__((noinline)) std::vector<double> modify(std::vector<double> data) {
    std::sort(data.begin(), data.end());
    return data;
}

std::vector<double> blah(std::vector<double> v) {
    v = modify(v);
    return v;
}

您可以查看不同编译器生成的汇编代码,这与it技术有关。这里我使用具有O3优化的clang 4.0: https://godbolt.org/g/xa2Dhf。如果您仔细查看汇编代码,您将会看到在blah中调用了operator new,这证明blah确实是执行了复制操作以调用modify函数。
当然,如果进行了内联,编译器应该很容易删除复制操作。

2
在C++11中,编译器可以确定在函数中使用后重新分配了bigData,并将其作为rvalue传递,但是与RVO(从c++17开始)不同,没有保证。对于至少std::vector,您可以通过调用modify(std::move(bigData))来确保发生这种情况,这将从rvalue引用构造modify中的值,它不能使用RVO进行优化,因为它是函数参数,该优化明确排除(此处的第3点)。然而,编译器应该理解返回值是一个r-value,并将其移回到big-data中。
我不确定是否有一些编译器会省略从对象移动到函数中,然后再从函数中移回对象,但我知道没有什么可以明确允许它,而且由于移动构造函数可能具有可观察的副作用,这可能意味着它不被允许(请参见上面链接中的注意事项部分)。

2
这真的是编译器特定的,取决于您如何操作数据(是否修改数据)。大多数情况下,除非您真正进行基准测试,否则不应该期望编译器进行这种优化。我使用VS2012编译器进行了一些测试,虽然我们没有修改数据,但它仍执行了复制操作。
请看一下这篇文章(Does the compiler optimize the function parameters passed by value?),希望对您有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接