【问题标题】:Why is copy constructor not called为什么不调用复制构造函数
【发布时间】:2014-01-14 06:55:50
【问题描述】:

这里是一个简单的类头文件和一个主程序。在主程序中,我认为复制构造函数在三种情况下被调用:初始化(显式复制),函数参数传值,函数传值。但是,似乎没有要求其中之一,我认为 (3) 或 (4) 在 cmets 中编号。调用哪个数字 (1) - (4)?谢谢。

X.h:

#include <iostream>

class X
{
public:
    X() {std::cout << "default constructor \n";}
    X(const X& x) { std::cout << "copy constructor \n";}
};

主要:

#include "X.h"

X returnX(X b)  // (1) pass by value - call copy constructor?
{
    X c = b;  // (2) explicit copy - call copy constructor?
    return b;  // (3) return by value - call copy constructor?
}

int main()
{
    X a; // calls default constructor

    std::cout << "calling returnX \n\n";
    X d = returnX(a);  // (4) explicit copy - call copy constructor?
    std::cout << "back in main \n";
}

输出:

default constructor
calling returnX

copy constructor
copy constructor
copy constructor 
back in main

【问题讨论】:

  • 允许编译器对其进行优化。

标签: c++ copy-constructor pass-by-value return-by-value


【解决方案1】:

由于复制在 C++ 中经常发生,而且成本可能很高,因此允许编译器省略某些复制(和移动)结构。即使省略的构造函数和/或析构函数具有像程序中的输出这样的副作用(也就是说,它并不是真正的优化,因为使用和不使用复制省略的行为是不同的),这种复制省略也是允许的。

根据 12.8 [class.copy] 第 31 段,有四个基本的地方可以应用复制省略:

  1. return 语句中直接返回与函数返回类型具有相同类型的局部变量。
  2. throw 语句中,最里面的try 块中的自动变量的副本可以在抛出对象时被省略。
  3. 当临时对象未绑定到引用复制时,可以省略它。
  4. catch 子句按值捕获对象并且与throw 语句中的对象具有相同类型时,可以省略副本。

确切的规则稍微复杂一些,但我认为这是它的要点。鉴于复制省略的规则相当严格,很容易抑制复制省略:最简单的方法是使用identity() 函数:

template <typename T>
T const& identity(T const& object) {
    return object;
}
...
X d = identity(returnX(a));

(不过,这个版本也禁止移动构造;使用T&amp;&amp; 推断类型并适当地返回它应该可以使移动构造成为可能,但我不太确定返回类型和返回语句应该是什么)。

【讨论】:

  • 警告:此答案早于 C++17,其中规则不同(尽管结果可能相同)。
【解决方案2】:

4 号正在复制临时文件。它是copy elision 的候选对象。即在某些条件下,允许编译器消除对复制构造函数的调用,即使复制构造函数有副作用。

【讨论】:

  • 实际上 3 和 4 都是复制省略的候选者。输出可能只包含 2 个复制结构
  • @DavidRodríguez-dribeas:我认为 NRVO 被禁止用于参数,不是吗?
  • @DavidRodríguez-dribeas:参数不允许复制省略。只有局部自动变量(不包括参数)有资格进行复制省略。但是,允许移动参数(下一段)。
  • @DietmarKühl(和 Benjamin):我的错,我读的代码是 return c;,而不是 return b;
猜你喜欢
  • 2021-02-18
  • 1970-01-01
  • 1970-01-01
  • 2021-05-14
  • 2012-02-28
  • 2015-06-10
  • 2012-06-28
相关资源
最近更新 更多