Understanding C++ copy constructor behavior - c++

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;
}

Related

Class destructor is causing problem with overloading + operator

I can't figure out what is the problem with my C++ class (using Visual Studio). Visual Studio is not giving any desired output, just saying " exited with code -1073741819". I created a class named Complex using raw pointers, when no-args or parameterized constructor is called, memory is allocated using new int and when variable goes out of scope, destructor deallocates memory using delete keywords. The only problem i am facing is that, my + operator overloading causing problem and i am pretty sure that this problem is related to destructor, when i remove destructor code, + operator works just fine. Or when I don't use + operator, also then program works fine. Please help me by figuring out code. Please don't say to me that "you don't need raw pointers here", actually i have been told to do so (using only pointers). I am stuck on this for many hours.
Here is my code, please go through it , including + operator overloading code and destructor code.
#include<iostream>
using namespace std;
class Complex {
private:
int *real;
int *complex;
public:
// some declarations
Complex();
Complex(int, int);
Complex(const Complex& source);
Complex operator+ (const Complex& rhs);
Complex& operator= (const Complex& rhs);
void disp() {
cout << "(" << *real << "," << *complex << ")" << endl;
}
// destructor
~Complex() {
delete real;
real = nullptr;
delete complex;
complex = nullptr;
}
};
// no-args constructor
Complex::Complex() {
real = new int;
*real = 0;
complex = new int;
*complex = 0;
}
// parameterized constructor
Complex::Complex(int x, int y) : Complex() {
*real = x;
*complex = y;
}
//copy constructor
Complex::Complex(const Complex& source) {
*(this->real) = *(source.real);
*(this->complex) = *(source.complex);
}
// overloading + operator
Complex Complex::operator+ (const Complex &rhs) {
int a, b;
a = *(this->real) + *(rhs.real);
b = *(this->complex) + *(rhs.complex);
Complex temp(a,b);
return temp;
}
// overloading = operator
Complex& Complex::operator= (const Complex& rhs) {
*(this->real) = *(rhs.real);
*(this->complex) = *(rhs.complex);
return *this;
}
int main() {
Complex n1(5,-9);
Complex n2(5,-1);
Complex n3;
n3=n1 + n2;
n3.disp();
return 0;
}
You don't allocate any memory in your copy constructor, so your assignments happen to uninitialized memory.
Complex::Complex(const Complex& source) {
*(this->real) = *(source.real);
*(this->complex) = *(source.complex);
}
If I change it to this:
Complex::Complex(const Complex& source) : Complex() {
*(this->real) = *(source.real);
*(this->complex) = *(source.complex);
}
Your program outputs (10,-10)
EDIT: Question in the comments.
I have added a few printouts to your program to show exactly what is going on:
#include<iostream>
using namespace std;
class Complex {
private:
int* real;
int* complex;
public:
// some declarations
Complex();
Complex(int, int);
Complex(const Complex& source);
Complex operator+ (const Complex& rhs);
Complex& operator= (const Complex& rhs);
void disp() {
cout << "(" << *real << "," << *complex << ")" << endl;
}
// destructor
~Complex() {
std::cout << "destructor" << std::endl;
delete real;
real = nullptr;
delete complex;
complex = nullptr;
}
};
// no-args constructor
Complex::Complex() {
std::cout << "constructor" << std::endl;
real = new int;
*real = 0;
complex = new int;
*complex = 0;
}
// parameterized constructor
Complex::Complex(int x, int y) : Complex() {
std::cout << "(x,y)constructor" << std::endl;
*real = x;
*complex = y;
}
//copy constructor
Complex::Complex(const Complex& source) : Complex() {
std::cout << "copy constructor" << std::endl;
*(this->real) = *(source.real);
*(this->complex) = *(source.complex);
}
// overloading + operator
Complex Complex::operator+ (const Complex& rhs) {
std::cout << "op+" << std::endl;
int a, b;
a = *(this->real) + *(rhs.real);
b = *(this->complex) + *(rhs.complex);
Complex temp(a, b);
return temp;
}
// overloading = operator
Complex& Complex::operator= (const Complex& rhs) {
std::cout << "op=" << std::endl;
*(this->real) = *(rhs.real);
*(this->complex) = *(rhs.complex);
return *this;
}
int main() {
Complex n1(5, -9);
Complex n2(5, -1);
Complex n3;
n3 = n1 + n2;
n3.disp();
return 0;
}
Now running your program results this:
constructor
(x,y)constructor
constructor
(x,y)constructor
constructor
op+
constructor
(x,y)constructor
constructor
copy constructor
destructor
op=
destructor
(10,-10)
destructor
destructor
destructor
As you can see, there is a "copy constructor" in there. Specifically this line: n3 = n1 + n2; results in this printout:
op+ // n1 + n2
constructor // base constructor from param constructor
(x,y)constructor // constructing the return value: Complex temp(a, b);
constructor // base constructor from copy constructor
copy constructor // copying from temp to the return value
destructor // destroying temp
op= // assigning the return value to n3
destructor // destroying the return value
Do note btw, that this was compiled in debug mode. If I compile in release mode the output changes:
constructor
(x,y)constructor
constructor
(x,y)constructor
constructor
op+
constructor
(x,y)constructor
op=
destructor
(10,-10)
destructor
destructor
destructor
The pertinent point here is that the compiler managed to optimize out the copy constructor, by recognizing that there is no point in constructing temp only to then copy and destroy it. But this only happens when optimization is turned on.
I'm suspecting that your parameterized constructor is the problem... In your parameterized constructor, you are creating a Complex class object, which takes the *real and *complex pointers, pointing it to the passed in integers(x and y). No memory is allocated hence when your program ends, your destructor gets called and attempts to deallocate memory inside n1 and n2 that were never dynamically allocated.
I haven't touched C++ in a few months, so I could be wrong. Feel free to check and get back to me on your results.

Why is copy constructor called rather than move constructor?

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&&)
}

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

Getting garbage value while doing chaining of assignment of class objects, using assignment operator overloading which returns class object by value

In assignment operator overloading, If I return the object by reference like below
One& operator=( const One& obj).
Then program works fine.
But if when I return by value, like below
One operator=( const One& obj)
Then o1 gets garbage value. Can anybody explain why return by value does not work in assignment operator overloading?
class One
{
public:
One(int a1, int b1) {
a = a1; b = b1;
}
int a;
int b;
One operator=( const One& obj) {
cout<<"\nOperator= is called\n"; a = obj.a; b = obj.b;
}
};
int main()
{
One o1(5,5);
One o2(10,10);
One o3(15,15);
cout << "\no1.a=" << o1.a << ", o1.b=" << o1.b << endl;
o1 = o2 = o3;
cout << "\no1.a=" <<o1.a << ", o1.b=" << o1.b << endl;
cout << "\no2.a=" <<o2.a << ", o2.b=" << o2.b << endl;
cout << "\no3.a=" <<o3.a << ", o3.b=" << o3.b << endl;
return 0;
}
Output:
o1.a=-13360, o1.b=0
o2.a=15, o2.b=15
o3.a=15, o3.b=15
Why o1 object showing garbage value in case of return by value in assignment operator. It works fine when return by reference. why?
o1 = o2 = o3; is evaluated as o1 = (o2 = o3);
That requires o2 = o3 to return something, and o1 is set to that value. But your overload currently doesn't. (Formally it means that the behaviour of your code is undefined). If you rewrite to
One& operator=(const One& obj)
{
std::cout << "\nOperator= is called\n";
a = obj.a;
b = obj.b;
return *this; // i.e. return a reference to self.
}
then all will be well. That said, the cool cats will use
One& operator=(One obj/*pass by value to exploit compiler optimisations*/)
{
std::cout << "\nOperator= is called\n";
std::swap(*this, obj);
return *this;
}
Reference: What is the copy-and-swap idiom?
The code of the = operator should be this:
One & operator=(const One& obj)
{
cout << "\nOperator= is called\n";
a = obj.a;
b = obj.b;
return *this;
}
One operator=( const One& obj)
{ cout<<"\nOperator= is called\n"; a = obj.a; b = obj.b; }
You do not have any return expression in your function definition, resulting in undefined behavior. That's why the operator does not work as it should.
In case you are using the gcc compiler, I would suggest you enable the -Wall option, which would have produced a warning, indicating the failure. In case you are using sth different there's probably an equivalent option available.
You may also want to take a look at the Copy-and-Swap Idiom which provides an advanced insight in the creation of a properly working copy-assignment operator.