C ++按值返回

时间:2012-07-14 16:44:32

标签: c++ function copy-constructor

从下面的代码我期望CA类可以调用以下代码

  1. 构造函数创建函数foo
  2. 返回的临时对象
  3. 复制构造函数以创建要传递给主
  4. 中的变量a的变量
  5. 另一个复制构造函数,它将根据函数返回的值创建a变量。
  6. 为什么不是这样?我的结果只是

    A
    

    虽然我在期待

    ABB
    

    因此只调用构造函数。编译器是在幕后优化还是我错过了一些C ++概念?

    class CA{
    public:
       CA(){ std::cout << "A"; }
       CA( const CA& ){ std::cout << "B"; }
       CA& operator=(const CA& ){ std::cout << "C";return *this; }
    };
    
    CA foo(){
          return CA();
    }
    
    int main(){
     CA a = foo();    
    }
    

2 个答案:

答案 0 :(得分:8)

  

编译器是在幕后优化还是我错过了一些C ++概念?

现货!它被称为复制省略。在谷歌上查找RVO和NRVO。你也应该查看三个规则。

复制elision是允许编译器执行的唯一影响可观察行为的优化。出于这个原因,您不应该在复制构造函数中放置重要的逻辑。

答案 1 :(得分:0)

C ++中至少有两种“优化”类型。

  • 第一种是语言规范明确引入的特定优化。

  • 第二种是编译器在“as-if”规则下进行的所有那些疯狂和不可预测的优化(即只要程序的可观察行为保持不变,编译器就可以做任何事情。)

(有些人可能会说只有第二种优化是真正的优化。)

你在这里看到的是第一种优化。执行多步复制操作时,语言规范明确总是允许编译器消除中间临时副本。

此外,C ++ 03及更高版本的语言规范更进一步:它们明确允许编译器执行“命名返回值优化”(NRVO),这实际上消除了命名(非临时) )对象。

两者都减少了程序中的复制操作次数。

即使它们改变了程序的可观察行为,也允许C ++中的这种复制消除优化,即第一类优化有时会违反对第二类的限制。在您的情况下,即使您将I / O操作插入到复制构造函数中,仍然允许编译器消除该构造函数的调用。

您发布的代码不需要NRVO。一个好的C ++ 98编译器应该能够产生你观察到的结果。如果你想看看你的编译器在这种情况下是否做了NRVO,你可能想尝试这个

CA foo(){
  Ca ca;
  return ca;
}