11

在这段代码中:

#include <iostream>

using std::cout;

class Foo {
    public:
        Foo(): egg(0) {}
        Foo(const Foo& other): egg(1) {}

        int egg;
};

Foo bar() {
    Foo baz;
    baz.egg = 3;
    return baz;
}

int main(void) {
    Foo spam(bar());
    cout << spam.egg;
    return 0;
}

输出是3,而我期望它是1

这意味着复制构造函数不会在该行中调用Foo spam(bar())

我想这是因为该bar函数不返回引用。

你能解释一下初始化时到底发生了spam什么吗?

如果这是一个愚蠢的问题,我提前道歉。

谢谢!

4

1 回答 1

19

复制/移动省略是所谓“ as-if ”规则的唯一允许例外,它通常限制编译器允许对程序执行的转换类型(例如优化)。

该规则旨在允许编译器执行他们希望的任何优化,只要转换后的程序“就好像”它是原始程序一样工作。但是,有一个重要的例外。

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

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。[...]这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

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

[...]

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

[...]

换言之,在适用 12.8/31 条款的情况下,您永远不应依赖调用或不调用复制构造函数或移动构造函数。

于 2013-05-02T18:09:32.283 回答