C++运算符重载和复制构造函数

7
我很难理解以下内容(特别是情况b): (假设我定义了一个赋值运算符、加法运算符和复制构造函数,只是为了输出它们被调用的事实)
情况a:
Simple a;
Simple b;
Simple c = a + b;

    The output is as follows:
    Simple constructor called
    Simple constructor called
    Simple add operator call
    Simple constructor called
    copy constructor called

-- 这都很好

场景 b(我无法理解的行为):

Simple d;
Simple e;
Simple f;
f = d + e;

    Simple constructor called
    Simple constructor called
    Simple constructor called
    Simple add operator called
    Simple constructor called
    copy constructor called
    assignment operator called

我想问的是,在场景b中,为什么复制构造函数在赋值运算符之前被调用?据我所知,复制构造函数只会在未初始化的对象上被调用。然而,在这种情况下,对象f已经在前面一行被初始化了。
您的解释将不胜感激。
很抱歉没有立即发布源代码(以及缺少缩进-我无法将其复制到文本区域中)。 这是它所有简单的代码。 我正在使用Visual Studio 2005。 不幸的是,我对它的工作原理不太熟悉,因此我无法指定传递给编译器的优化参数。
class Simple
{
public:
    Simple(void);
Simple operator +(const Simple& z_Simple) const;
Simple& operator =(const Simple& z_Simple);
Simple(const Simple& z_Copy);
int m_Width;
int m_Height;
public:
~Simple(void);
};


#include "Simple.h"
#include <iostream>

using std::cout;
using std::endl;

Simple::Simple(void)
{
this->m_Height = 0;
this->m_Width = 0;
cout << "Simple constructor called" << endl;
}

Simple::Simple(const Simple& z_Copy)
{
cout << "copy constructor called" << endl;
this->m_Height = z_Copy.m_Height;
this->m_Width = z_Copy.m_Width;
}

Simple& Simple::operator =(const Simple &z_Simple)
{
cout << "assignment operator called" << endl;
this->m_Height = z_Simple.m_Height;
this->m_Width = z_Simple.m_Width;   
return *this;
}


Simple Simple::operator +(const Simple &z_Simple) const
{
cout << "Simple add operator called" << endl;
int y_Height = this->m_Height + z_Simple.m_Height;
int y_Width = this->m_Width + z_Simple.m_Width;
Simple y_Ret;
y_Ret.m_Height = y_Height;
y_Ret.m_Width = y_Width;
return y_Ret;
}

Simple::~Simple(void)
{
cout << "destructor called" << endl;
}

当然,Nemo的解释是我这个初学者可以理解的 :)
将优化级别更改为/O2后,我可以看到场景b的输出如下(这也是我预期的)
    Simple constructor called
    Simple constructor called
    Simple constructor called
    Simple add operator called
    Simple constructor called
    assignment operator called

感谢大家提供的建议。

4
实际上这取决于你如何重载运算符,尤其是复制赋值运算符 +。除非你公布代码,否则任何解释都只是猜测。 - Alok Save
1
@Shahzeb:第一个中没有赋值。这就是为什么没有调用赋值运算符的原因。不要让“=”符号欺骗你。最后一个“Simple constructor called”可能是在加法运算符内部产生的。 - R. Martinho Fernandes
1
编译器也可能将 Simple f; f = d+e; 编译为 Simple f; Simple temp = d+e; f = temp;。(事实上,这是我猜测正在发生的情况。)但是,如果没有看到完整的代码并知道您使用的编译器和优化标志,就无法确定。 - Nemo
+1 显示类定义。不过,我强烈建议声明 += 运算符来解决这个“问题”。 - real4x
我无法重现你的输出。尝试启用优化级别。编辑:哦,实际上我可以通过-fno-elide-constructors来重现它。 - Kerrek SB
1个回答

5
你的+运算符返回一个对象,这个对象是按值传递的,如果编译器没有对其进行省略,可能会导致调用复制构造函数。
Simple Simple::operator +(const Simple &z_Simple) const
{
    //......
    Simple y_Ret;
    //......
    return y_Ret;
}

代码:

Simple d;
Simple e;
Simple f;
f = d + e;

以下是逐步分析:

Simple constructor called     ---> creation of `d`
Simple constructor called     ---> creation of `e`
Simple constructor called     ---> creation of `f`
Simple add operator called    ---> Inside Addition operator
Simple constructor called     ---> creation of local `y_Ret`
copy constructor called       ---> `y_Ret` returned by value 
assignment operator called    ---> Result returned by `+` used for `=`  

因此,实际上最后一个复制构造函数是在局部对象 y_Ret 的临时副本上被调用的,然后将该局部副本用作分配给 f 的 rvalue。这样理解对吗? - Michael
@bojarski:抱歉回复晚了,被卡住了。是的,那是正确的。 - Alok Save

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接