Why is copy constructor called rather than move constructor? - c++

I have the following code:
#include <bits/stdc++.h>
using namespace std;
class A {
public:
A(const A& a) noexcept { cout << "copy constructor" << endl; }
A& operator=(const A& a) noexcept { cout << "copy assignment operator" << endl; }
A(A&& a) noexcept { cout << "move constructor" << endl; }
A& operator=(A&& a) noexcept { cout << "move assignment operator" << endl; }
A() { cout << "default constructor" << endl; }
};
vector<A> aList;
void AddData(const A&& a)
{
aList.push_back(std::move(a));
}
int main()
{
AddData(A());
return 0;
}
The output is default constructor copy constructor. please tell me is the rvalue reference push_back(T&&)called? And when is copy constructor called?

The issue is with the a parameter in AddData():
void AddData(const A&& a) // <-- const reference!!!
{
aList.push_back(std::move(a)); // selects push_back(const A&)
}
The a parameter above is a const rvalue reference. You are marking with std::move() a const object.
Marking a const object with std::move() for moving has no effect when it comes to move semantics because you can't move from a const object (i.e., you need to alter the moved-from object, but it is const-qualified).
An rvalue reference doesn't bind to a const object, but a const lvalue reference does. As a result, the push_back(const A&) overload is selected instead of the push_back(A&&) one, and therefore the A object is copy constructed.
Solution
Use a non-const rvalue reference instead:
void AddData(A&& a) // <-- non-const reference
{
aList.push_back(std::move(a)); // selects push_back(A&&)
}

Related

Why the copy constructor is called when I add a different object which is an argument in copy constructor?

I don't understand why the copy constructor is called while i am adding e to c.
struct A {};
struct B {
B() { std :: cout << "B Constructor" << std :: endl; }
B(const A&) { std :: cout << "B Copy" << std :: endl;}
const B operator +(const B& arg);
};
const B B::operator +(const B& arg) {
std :: cout << "+" << std :: endl;
return B();
}
int main() {
B c;
A e;
c + e;
}
It's not the copy constructor being called, it's
B(const A&);
The copy constructor always has such a signature:
B(const B&);
As you haven't provided one, the compiler generates a copy constructor for you, but this one is indeed not called: you have an operator+ for B, which accepts a const B&, but the other operand is of type A. As the constructor mentioned first (B(const A&)) is implicit, this works out - a temporary B is instantiated from the A object named e, and the operator is invoked.
To make the output in your example more intuitive, consider changing the constructor B(const& A) to
B(const A&) { std::cout << "Construct B from A\n"; }

Move semantics in C++11

I would like to fully understand move semantics in C++11. So I have written a couple of classes to see when different constructors are called:
#include <iostream>
using namespace std;
class A {
public:
A() : a1_(0) {std::cout << "Calling constructor" << std::endl;}
A(A&& other) {
std::cout << "Calling move constructor" << std::endl;
a1_ = other.a1_;
other.a1_ = 0;
}
// Move assignment operator.
A& operator=(A&& other) {
std::cout << "Calling move operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
other.a1_ = 0;
}
return *this;
}
// Copy constructor.
A(const A& other) {
std::cout << "Calling copy constructor" << std::endl;
a1_ = other.a1_;
}
// Copy assignment operator.
A& operator=(const A& other) {
std::cout << "Calling copy assignment operator" << std::endl;
if (this != &other) {
a1_ = other.a1_;
}
return *this;
}
private:
int a1_;
};
class B {
A oA_;
public:
B() {}
void setoA(A a) {oA_ = a;}
A getoA() {return oA_;}
};
A createA() {
A a1;
return a1;
}
B createB() {
B tmpB;
A tmpA;
tmpB.setoA(tmpA);
return tmpB;
}
int main() {
B b;
A a;
b.setoA(a);
std::cout << "**************************" << std::endl;
b.setoA(createA());
std::cout << "**************************" << std::endl;
b.setoA(std::move(createA()));
std::cout << "**************************" << std::endl;
B b2;
b2.setoA(b.getoA());
std::cout << "**************************" << std::endl;
createB();
return 0;
}
When I check the output of this code:
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling move constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling copy constructor
Calling copy assignment operator
++++++++++++++++++++++++++++++++++
Calling constructor
Calling constructor
Calling copy constructor
Calling copy assignment operator
I have some doubts here:
I thought that if you pass r-value, move constructor will be called, is that right? Isn't this b.setoA(createA()); an r-value?
How can I make move constructor/operator being called?
First of all in first section, why is constructor being called twice?
Because you construct both an B and a A with the former having its own instance of A, which the first (the unexpected) constructor call comes from.
I thought that if you pass r-value move constructor will be called, is that right? Isn't this b.setoA(createA()); an r-value?
The constructor is called from within createA (and yes, return value is an r-value), however, copy elision occurs and the object is directly instantiated in the parameter variable of setoA.
Within setoA, however, the copy assignment is selected, as now a is an l-value. If you want to move, you need:
void setoA(A a) { oA_ = std::move(a); }
Some copies and moves may be optionally elided by the compiler. To prevent this, use -fno-elide-constructors in GCC and Clang. In addition, some move elisions became mandatory in C++17, so to force the compiler to use C++11 move semantics, use -std=c++11 as well.

C++ move-assignment prevents copy-swap idiom

In C++, copy-swap idiom is typically implemented like this:
C& operator=(C rhs)
{
swap(*this, rhs);
return *this;
}
Now, if I want to add a move-assignment operator, it is supposed to look like this:
C& operator=(C&& rhs)
{
swap(*this, rhs);
return *this;
}
However, this creates ambiguity about which assignment operator should be called and compilers rightfully complain about it. So my question is the following: If I want to support copy-swap idiom together with move-assignment semantics what am I supposed to do?
Or is this a non-issue as having a move-copy constructor and copy-swap idiom, one doesn't really benefit from having a move-assignment operator?
After asking this question, I've written a code that demonstrates that move-assignment may result in fewer function calls than copy-swap idiom. First let me present my copy-swap version. Please bear with me; it appears like a long but a simple example:
#include <algorithm>
#include <iostream>
#include <new>
using namespace std;
bool printOutput = false;
void* operator new(std::size_t sz)
{
if (printOutput)
{
cout << "sz = " << sz << endl;
}
return std::malloc(sz);
}
class C
{
int* data;
public:
C() : data(nullptr)
{
if (printOutput)
{
cout << "C() called" << endl;
}
}
C(int data) : data(new int)
{
if (printOutput)
{
cout << "C(data) called" << endl;
}
*(this->data) = data;
}
C(const C& rhs) : data(new int)
{
if (printOutput)
{
cout << "C(&rhs) called" << endl;
}
*data = *(rhs.data);
}
C(C&& rhs) : C()
{
if (printOutput)
{
cout << "C(&&rhs) called" << endl;
}
swap(*this, rhs);
}
C& operator=(C rhs)
{
if (printOutput)
{
cout << "operator= called" << endl;
}
swap(*this, rhs);
return *this;
}
C operator+(const C& rhs)
{
C result(*data + *(rhs.data));
return result;
}
friend void swap(C& lhs, C& rhs);
~C()
{
delete data;
}
};
void swap(C& lhs, C& rhs)
{
std::swap(lhs.data, rhs.data);
}
int main()
{
C c1(7);
C c2;
printOutput = true;
c2 = c1 + c1;
return 0;
}
I have compiled this with g++ using the -fno-elide-constructors option as I want to see the no optimization behavior. The result is the following:
sz = 4
C(data) called // (due to the declaration of result)
C() called // (called from the rvalue copy-constructor)
C(&&rhs) called // (called due to copy to return temporary)
C() called // (called from the rvalue copy-constructor)
C(&&rhs) called // (called due to pass-by-value in the assignment operator)
operator= called
Now, if I choose not to make copy-swap idiom in the assignment operator, I will have something like this:
C& operator=(const C& rhs)
{
if (printOutput)
{
cout << "operator=(const C&) called" << endl;
}
if (this != &rhs)
{
delete data;
data = new int;
*data = *(rhs.data);
}
return *this;
}
This allows me to have the move-assignment operator as follows:
C& operator=(C&& rhs)
{
if (printOutput)
{
cout << "operator=(C&&) called" << endl;
}
swap(*this, rhs);
return *this;
}
Now, with everything else being the same, I get the following output:
sz = 4
C(data) called // (due to the declaration of result)
C() called // (called from the rvalue copy-constructor)
C(&&rhs) called // (called due to copy to return temporary)
operator=(C&&) called // (move-assignment)
As you can see this results in fewer function calls. Actually the last three function calls in the copySwapIdiom has now dropped down to a single function call. This is expected as we no longer pass the assignment operator parameter by value, hence no construction happens there.
However, I do not benefit from the beauty of copy-swap idiom in the assignment operator. Any insight is much appreciated.
There actually isn't a need to implement the move assignment operator if you provide a valid move constructor.
class Foo
{
public:
explicit Foo(Bar bar)
: bar(bar)
{ }
Foo(const Foo& other)
: bar(other.bar)
{ }
Foo(Foo&& other)
: bar(other.bar)
{ }
// other will be initialized using the move constructor if the actual
// argument in the assignment statement is an rvalue
Foo& operator=(Foo other)
{
std::swap(bar, other.bar);
return *this;
}
The motivation behind the copy-swap idiom here is to forward the copy/move work to constructors, so that you don't duplicate work for both constructors and assignment operators. That said,
C& operator=(C rhs) noexcept;
means to replace the pair
C& operator=(const C& rhs);
C& operator=(C&& rhs) noexcept;
Whether C& operator=(C rhs) noexcept; performs copy or move assignment depends on how rhs is constructed. For example,
a = std::move(b); // rhs is move-constructed from r-value std::move(b), and thus move-assignment
c = d; // rhs is copy-constructed from l-value d, and thus copy-assignment

Understanding C++ copy constructor behavior

This is my code:
#include <iostream>
using namespace std;
class A
{
int i;
public:
A(int v) : i(v) { }
A(const A& r) : i(r.i) {
cout << "Copy constructor" << endl;
}
A operator=(const A& r) {
cout << "Assignment function" << endl;
return r;
}
void show() {
cout << i << endl;
}
};
int main()
{
A a(1);
A b(2);
a = b;
a.show();
return 0;
}
Value of b is 2 and value of a is 1. In 'main', b is copied into a and this the output I get:
Assignment function
Copy constructor
This is understandable, but the output for a.show() comes out be 1. I can't understand this. How? Because b is copied into a using the copy constructor so shouldn't a.i have the value of b.i?
b is copied into a using the assignment operator, not the copy constructor. And your assignment operator doesn't assign i, so a.i keeps its original value.
The copy constructor you are seeing is for the return value of operator=. It is more customary to return the left-hand-side by reference, not the right-hand-side by value:
A& operator=(const A& r) {
cout << "Assignment function" << endl;
i = r.i;
return *this;
}
When you define the assignment operator you have to do all of the work to copy the data.
A operator=(const A& r) {
cout << "Assignment function" << endl;
i = r.i;
return r;
}
so a = b is calling your assignment operator (obviously, hence your output). But right now it isn't copying anything.
The assignment operator doesn't do anything to the "assigned to" object. The copy constructor call you see reported is from the creation of the assignment return value.
Your copy assignment should probably look loke this:
A& A::operator= (A const& other) {
// output
this->i = other.i;
return *this;
}

Ambiguous overload for operator= using move assign and pass by value copy assign

If I define a copy assignment operator that invokes the copy constructor using pass by value for class thing:
thing& operator= (thing x) {
and a move assignment operator for the same class:
thing& operator= (thing&& x) {
Trying to invoke the move assignment results in an error from gcc:
error: ambiguous overload for ‘operator=’ (operand types are ‘thing’ and ‘std::remove_reference<thing&>::type {aka thing}’)
However, if the copy assign instead uses pass by reference:
thing& operator= (thing& x) {
Compilation is fine, and both operators can be invoked. Why is this?
Complete C++11 test code:
#include <iostream>
#include <utility>
using namespace std;
class thing {
public:
thing () { }
thing (thing& x) {
cout << "Copy constructor.\n";
}
thing (thing&& x) {
cout << "Move constructor.\n";
}
thing& operator= (thing x) {
cout << "Copy assign using pass by value.\n";
return *this;
}
thing& operator= (thing&& x) {
cout << "Move assign.\n";
return *this;
}
};
int main (void) {
thing a, b;
// Invoke move assignment:
a = move(b);
return 0;
}
Calling move(b) returns an rvalue.
Both operator=(thing &&x) and operator=(thing x) can accept rvalues as input.
As such, the two overloads are ambiguous and the compiler rightfully complains because it can't choose between them.