0

I know the expression like MyClass a = b is a copy initialization and it'll call the copy constructor.

What about MyClass a = b + c?

I have tried it. In visual studio 2015, it seems the expression is not a copy initialization nor a copy assignment.So what is it?

Below is the code I tested:

class MyClass
{
public:
    MyClass()
    {
        cout << "default constructor has been called!" << endl;
    }
    MyClass(const MyClass& cls)
    {
        cout << "copy constructor has been called!" << endl;
    }
    MyClass operator+(const MyClass& cls) const
    {
        cout << "operator + has been called!" << endl;
        return MyClass();
    }
    MyClass& operator=(const MyClass& cls)
    {
        cout << "operator = has been called!" << endl;
        return *this;
    }
};

int main()
{
    MyClass b, c;
    MyClass a = b + c;
    return 0;
}

And the output is

default constructor has been called!
default constructor has been called! 
operator + has been called!
default constructor has been called! 
AK2806
  • 3
  • 5
  • `MyClass& operator=(const MyClass& cls)` -- This function invokes undefined behavior since you failed to return a value. – PaulMcKenzie Nov 20 '16 at 08:06
  • Sorry for my mistake. I have corrected it.However I don't think it's a serious misleading in this question. – AK2806 Nov 22 '16 at 03:22
  • It's serious enough that it plays a part in how the program will work. No return value, and anything can happen. – PaulMcKenzie Nov 22 '16 at 03:28

3 Answers3

2

The copy constructor may be elided in such a case.

2

From a c++ type perslective, there's no difference between

MyClass a = b + c;

and

MyClass a = MyClass();

since operator+ returns an rvalue MyClass. And since you just created exactly the object that you want a to be, it just makes that object directly into a.

This is described in the first example here: http://en.cppreference.com/w/cpp/language/copy_elision

xaxxon
  • 19,189
  • 5
  • 50
  • 80
0

What you experience is called return value optimization (see What are copy elision and return value optimization?).

The compiler optimizes code (to minimize objects created) and makes a actually be the local object declared and returned by your+ operator. Then, there is no copy constructor used. This is what you observe here.

To nicely observe this, change your code to see object memory adresses:

#include <iostream>
using namespace std;

class MyClass
{
public:
    MyClass()
    {
        cout << "default constructor has been called for " << std::hex << this << endl;
    }
    MyClass(const MyClass& cls)
    {
        cout << "copy constructor has been called for " << std::hex << this << " (copied from " << &cls << ")" << endl;
    }
    MyClass operator+(const MyClass& cls) const
    {
        cout << "operator + has been called!" << endl;
        MyClass res;
        cout << "operator + returns temporary object " << std::hex << &res << endl;
        return res;
    }
    MyClass& operator=(const MyClass& cls)
    {
        cout << "operator = has been called!" << endl;
        return *this;
    }
};

int main()
{
    MyClass b, c;
    MyClass a = b + c;
    cout << "a object is " << std::hex << &a << endl;
    return 0;
}

It outputs:

default constructor has been called for 0x7ffd44b769fd
default constructor has been called for 0x7ffd44b769fe
operator + has been called!
default constructor has been called for 0x7ffd44b769ff
operator + returns temporary object 0x7ffd44b769ff
a object is 0x7ffd44b769ff

You see that temporary object created in operator+ is the same as a (0x7ffd44b769ff), due to compiler optimization.

If you use g++, compile with -fno-elide-constructors to disable this compiler optimization. And the output is now:

default constructor has been called for 0x7ffd92847d1c
default constructor has been called for 0x7ffd92847d1d
operator + has been called!
default constructor has been called for 0x7ffd92847cff
operator + returns temporary object 0x7ffd92847cff
copy constructor has been called for 0x7ffd92847d1f (copied from 0x7ffd92847cff)
copy constructor has been called for 0x7ffd92847d1e (copied from 0x7ffd92847d1f)
a object is 0x7ffd92847d1e

You see that now operator+ creates a local object (0x7ffd92847cff), which is later copied as a temporary object for return statement (copying 0x7ffd92847cff to 0x7ffd92847d1f), which is finally used to construct a by copy (copying 0x7ffd92847d1f to 0x7ffd92847d1e).

Community
  • 1
  • 1
jpo38
  • 20,821
  • 10
  • 70
  • 151