NoOne
NoOne

Reputation: 35

Move constructor not getting called, instead copy constructor gets called

I am trying to call the move constructor but the copy constructor is getting called. What am I doing wrong?

#include <iostream>
#include <string.h>

class X
{
    char* name;
public:
    X(const char* p)
    {
        name = new char[strlen(p) + 1];
        strcpy(name, p);
        std::cout<<"Constructor: "<<name<<"; Address: "<<this<<std::endl;
    }

    ~X()
    {
        std::cout<<"Destructor: "<<name<<"; Address: "<<this<<std::endl;
        delete [] name;
    }

    X(const X& a)
    {
        name = new char[strlen(a.name) + 1];
        strcpy(name, a.name);
        std::cout<<"Copy Constructor: "<<name<<"; Address: "<<this<<"; made from: "<<&a<<std::endl;
    }

    X& operator=(const X& a)
    {
        if (name)
        {
            delete [] name;
        }

        name = new char[strlen(a.name) + 1];
        strcpy(name, a.name);
        std::cout<<"Assignment operator: "<<name<<"; Address: "<<this<<"; made from: "<<&a<<std::endl;

        return *this;
    }

    X operator+(const X& a)
    {
        std::string s1 = name;
        std::string s2 = a.name;
        s1.append(" ");
        s1.append(s2);

        X x(s1.c_str());

        std::cout<<"operator+: "<<s1.c_str()<<"; Address: "<<&x<<"; Created from"
            <<this<<" and "<<&a<<std::endl;

        return x;
    }

    // move copy constructor
    X(X&& a)
    {
        name = a.name;
        a.name = nullptr;
        std::cout<<"Move Copy Constructor: "<<name<<"; Address: "<<this<<std::endl;
    }

    friend X fun(const X& a);
};

X fun(const X& a)
{
    std::cout<<"Inside fun()"<<std::endl;
    X p = a;
    return p;
}

int main()
{
    X h("Harry");
    X r("Ron");

    std::cout<<"Trying to create a temporary object"<<std::endl;
    X a = fun(h + r);
    std::cout<<"Check above if a temporay object was created"<<std::endl;

    return 0;
}

O/P of the above program:

Constructor: Harry; Address: 0x79315dbc31b0
Constructor: Ron; Address: 0x79315dbc31c0
Trying to create a temporary object
Constructor: Harry Ron; Address: 0x79315dbc31e0
operator+: Harry Ron; Address: 0x79315dbc31e0; Created from0x79315dbc31b0 and 0x79315dbc31c0
Inside fun()
Copy Constructor: Harry Ron; Address: 0x79315dbc31d0; made from: 0x79315dbc31e0
Destructor: Harry Ron; Address: 0x79315dbc31e0
Check above if a temporay object was created
Destructor: Harry Ron; Address: 0x79315dbc31d0
Destructor: Ron; Address: 0x79315dbc31c0
Destructor: Harry; Address: 0x79315dbc31b0

Does it mean the program is not able to create a temporary object? I thought the object with address 0x79315dbc31e0 was a temporary object.

Note: Since my gcc is old I tried this code on one of the online C++ compilers that support C++11 and C++14.

Upvotes: 0

Views: 398

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118302

The call to the "Copy Constructor", immediately after "Inside fun()", is actually the call to the copy constructor from the following line, in fun():

X p = a;

That's the call to the copy constructor. You were obviously expecting a move constructor to be invoked as a result of:

X a = fun(h + r);

This temporary is completely "elided" away. This entire sequence:

X p = a;
return p;

Results in the compiler essentially constructing p as the return value from the function, so "return p" does nothing.

Then, because the return value from the function gets used to instantiate the a object in main(), the caller essentially passes main()'s "a", to fun(), as the object to be constructed by fun().

You can see for yourself, the sequence of these events, simply by stepping through your code with the debugger.

Upvotes: 2

Related Questions