Home > Mobile >  Understanding the reasoning between copy/move constructors and operators
Understanding the reasoning between copy/move constructors and operators

Time:12-16

I am trying to get the grasp of rvalue references and move semantics with a simple self-made example but I can't understand a specific part. I have created the following class:

class A {
public:
    A(int a) {
        cout << "Def constructor" << endl;
    }

    A(const A& var) {
        cout << "Copy constructor" << endl;
    }

    A(A&& var) {
        cout << "Move constructor" << endl;
    }

    A& operator=(const A& var) {
        cout << "Copy Assignment" << endl;
        return *this;
    }

    A& operator=(A&& var) {
        cout << "Move Assignment" << endl;
        return *this;
    }
};

I tried the following experiments to see if I can predict how the constructors/operators are going to be called:

  1. A a1(1) - The default constructor is going to be called. PREDICTED.
  2. A a2 = a1 - The copy constructor is going to be called. PREDICTED.
  3. a1 = a2 - The copy assignment operator is going to be called. PREDICTED.

Now, I created a simple function that just returns an A object.

A helper() {
   return A(1);
}
  1. A a3 = helper() - The default constructor is going to be called in order to create the object that the helper returns. The move constructor is not going to be called due to RVO. PREDICTED.
  2. a3 = helper() - The default constructor is going to be called in order to create the object that the helper returns. Then, the move assignment operator is going to be called. PREDICTED.

Now comes the part I don't understand. I created another function that is completely pointless. It takes an A object by value and it just returns it.

A helper_alt(A a) {
    return a;
}
  1. A a4 = helper_alt(a1) - This will call the copy constructor, to actually copy the object a1 in the function and then the move constructor. PREDICTED.
  2. a4 = helper_alt(a1) - This will call the copy constructor, to actually copy the object a1 in the function and then I thought that the move assignment operator is going to be called BUT as I saw, first, the move constructor is called and then the move assignment operator is called. HAVE NO IDEA.

Please, if any of what I said is wrong or you feel I might have not understood something, feel free to correct me.

My actual question: In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator?

CodePudding user response:

Congratulations, you found a core issue of C !

There are still a lot of discussions around the behavior you see with your example code.

There are suggestions like:

A&& helper_alt(A a) {
    std::cout << ".." << std::endl;
    return std::move(a);
}

This will do what you want, simply use the move assignment but emits a warning from g "warning: reference to local variable 'a' returned", even if the variable goes immediately out of scope.

Already other people found that problem and this is already made a c standard language core issue

Interestingly the issue was already found in 2010 but not solved until now...

To give you an answer to your question "In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator?" is, that also C committee does not have an answer until now. To be precise, there is a proposed solution and this one is accepted but until now not part of the language.

From: Comment Status

Amend paragraph 34 to explicitly exclude function parameters from copy elision. Amend paragraph 35 to include function parameters as eligible for move-construction.

  • Related