6

我有以下两个功能:

Class foo(Class arg)
{
    return arg;
}

Class bar(Class *arg)
{
    return *arg;
}

现在,当我只调用 foo(arg) 时,复制构造函数当然会被调用两次。当我单独调用 bar(&arg) 时,它只调用一次。因此,我希望

foo(bar(&arg));

复制构造函数在这里被调用了 3 次。但是,它仍然只调用了两次。这是为什么?编译器是否认识到不需要另一个副本?

提前致谢!

4

1 回答 1

6

编译器是否认识到不需要另一个副本?

确实如此。编译器正在执行复制/移动省略。这是所谓的“as-if”规则的唯一例外,它允许编译器(在某些情况下,如您的示例中的那个)忽略对类的复制或移动构造函数的调用,即使它们有边效果。

根据 C++11 标准的第 12.8/31 段:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被删除的较晚时间。没有优化就被破坏了。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以组合起来消除多个副本):

— 在return具有类返回类型的函数的语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

— [...]

— 当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到省略复制/移动的目标

— [...]

使用 GCC,您可以尝试使用-fno-elide-constructor编译标志来抑制这种优化,并查看在没有复制省略发生时编译器的行为。

于 2013-05-12T12:00:48.553 回答