当临时返回对象立即分配给另一个对象时调用复制构造函数

Is copy constructor called when the temporary returning object is assigned to another object immediately

本文关键字:一个对象 调用 复制 构造函数 返回 对象 分配      更新时间:2023-10-16

我在理解这段代码的输出如何像这样出现时遇到问题:

#include<iostream>
using namespace std;
class three_d
{float x,y,z;
public:
    three_d(){x=y=z=0;cout<<"ntDefault Constructor";}
    three_d(float a,float b,float c){x=a;y=b;z=c;cout<<"ntOverloaded Constructor";}
    three_d(const three_d &obj){x=obj.x;y=obj.y;z=obj.z;cout<<"ntCopy Constructor";}
    three_d operator+(three_d op2);
    three_d operator=(three_d op2);
    void show();
    ~three_d(){cout<<"ntDestructor Working !!";}
};
three_d three_d::operator+(three_d op2)
{
    x=x+op2.x;
    y=y+op2.y;
    z=z+op2.z;
    return *this; 
}
three_d three_d::operator=(three_d op1)
{
    x=op1.x;
    y=op1.y;
    z=op1.z;
    return *this;
}
void three_d::show()
{
    cout<<"nntValues are : x="<<x<<" y="<<y<<" and z="<<z<<"n";
}
int main()
{
    three_d ob1(2.1,2,2.2);
    three_d ob2(1,1,1), ob3;
    ob3=ob1+ob2;
    ob1.show();
    ob2.show();
    ob3.show();
    return 0;
}

输出为:

1. Overloaded Constructor 
2. Overloaded Constructor
3. Default Constructor
4. Copy Constructor
5. Copy Constructor
6. Destructor Working !!
7. Copy Constructor
8. Destructor Working !!
9. Destructor Working !!
10. Values are : x=3.1 y=3 and z=3.2
11. Values are : x=1 y=1 and z=1
12. Values are : x=3.1 y=3 and z=3.2
13. Destructor Working !!
14. Destructor Working !!
15. Destructor Working !!

所以我的问题是:

  • 在输出的第 5 行中,这个复制构造函数是干什么用的? 是用于*这个指针(但由于它是一个指针,我认为它不需要复制构造函数)?第四行是对象 op2(我想) ?
  • 如果上面的语句在重载"="时为真,为什么只使用一个复制构造函数(当它也有一个返回值时?
  • 临时(返回)对象何时被破坏?
  • 请解释输出是如何排序的。
  • 即使我将重载的"+"更改为这样:

    three_d three_d::运算符+(three_d op2)
    {three_d temp;
    temp.x=x+op2.x;
    temp.y=y+op2.y;
    temp.z=z+op2.z;
    返回温度;
    }

"=

"的复制构造函数的输出保持不变(尽管值将被更改),即只有 1 个 "=" 的复制构造函数。但是我认为"="必须有 2 个复制构造函数,1 个用于 op1 对象,其他用于 *this .
如果我在 main 中使用简单的赋值,例如 :
ob3=ob1;
则复制构造函数的调用是预期的两倍。请解释一下。

理解该语句的最佳方式,我认为您应该将其视为;

ob3.operator=(ob1.operator+(ob2));

4. Copy Constructor :这是从ob2创建一个临时对象,因为您按值调用operator+。我们称之为临时 tmp2
5. Copy Constructor :这是从ob1创建临时对象,因为您是从按值返回operator+。我们称之为临时 tmp1
6. Destructor Working !! :当operator+完成时,临时对象 TMP2 被破坏。
-->Important note hereVC++GCC编译器有趣地通过引用将从operator+返回的临时对象tmp1传递给operator=,即使operator=按值(副本)获取输入。这就是为什么您在此处看不到另一个复制构造函数的原因。[这需要专家解释]
7. Copy Constructor :这是从ob3创建另一个临时,因为您按值从operator=返回。让我们称之为最后一个临时 tmp3
8. Destructor Working !! :当operator+完成时,tmp1被破坏。
9. Destructor Working !! :当operator+完成时,tmp3将在作业结束时销毁。
当我看到编译器的结果GCC如下所示:

4.复制构造函数
5.复制构造函数
6.复制构造函数
7.析构函数工作!! 8.析构函数工作!! 9.析构函数工作!!

我所做的类似分析如下:

  1. TMP2 创建
  2. TMP1 创建
  3. TMP3 创建
  4. TMP3 销毁
  5. TMP1 销毁
  6. TMP2 销毁

注意:我们假设您知道使用签名定义operator+operator=的真实方法。(一个是友元函数,需要两个常量参数,另一个是通过引用等返回)

您的

operator+operator=都返回对象。它们是*this的副本.因此,对复制构造函数的调用。

如果想要避免调用复制构造函数,为了避免复制的成本,请更改这些函数以返回引用。

three_d const& three_d::operator+(three_d op2)
{
   x=x+op2.x;
   y=y+op2.y;
   z=z+op2.z;
   return *this; 
}
three_d const& three_d::operator=(three_d op1)
{
   x=op1.x;
   y=op1.y;
   z=op1.z;
   return *this;
}

附言

operator+函数修改操作数的 LHS。这种情况并不常见。在表达式中

a = b + c;

你不希望b被改变。这是值得思考的问题。

如果要以运行良好的方式实现这些功能,则应将它们更改为:

three_d three_d::operator+(three_d const& rhs) const
{
   three_d r(*this);
   r.x += rhs.x;
   r.y += rhs.y;
   r.z += rhs.z;
   return r; 
}
three_d& three_d::operator=(three_d const& rhs)
{
   if ( this != &rhs )
   {
      x = rhs.x;
      y = rhs.y;
      z = rhs.z;
   }
   return *this;
}
相关文章: