【问题标题】:Why the copy constructor is not called?为什么不调用复制构造函数?
【发布时间】:2013-05-02 17:55:34
【问题描述】:

在这段代码中:

#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初始化时到底发生了什么吗?

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

谢谢!

【问题讨论】:

  • 你是对的......因为 baz 是一个临时的,当它离开 bar 函数的范围时会被销毁。
  • 搜索返回值优化 (RVO)。这是允许 c++ 跳过调用复制构造函数的少数情况之一。
  • @John5342:谢谢!我不知道。

标签: c++ reference constructor copy-constructor return-value-optimization


【解决方案1】:

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

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

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

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

  • 在具有类返回类型的函数中的 return 语句中,当表达式是 具有相同 cv-unqualified 的非易失性自动对象(函数或 catch 子句参数除外) type 作为函数返回类型,可以通过构造省略复制/移动操作 自动对象直接转化为函数的返回值

[...]

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

[...]

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

【讨论】:

  • @AndyPowl:谢谢!这就是我一直在寻找的。​​span>
  • @segfolt:很高兴我能帮上忙;)
  • 规范的引用部分只去掉了这里的两个副本之一(从baz 到持有bar() 返回值的未命名临时副本)。第二个副本(从临时到spam)在引用部分的第三个要点允许的情况下被省略,您在引用中省略了...
猜你喜欢
  • 2021-02-18
  • 2014-01-14
  • 1970-01-01
  • 2021-05-14
  • 2012-02-28
  • 2015-06-10
  • 2012-06-28
相关资源
最近更新 更多