Why does assignment operator not work as expected? - c++

UPD: I can see now how stupid this question is, it's just my misunderstanding of C++ constructions.
I got stuck with operator assignment problem - it doesn't work as expected. Here's the example code:
#include <iostream>
class TestClass{
private:
int pop;
public:
TestClass(){
std::cout<<"Default Constuctor\n";
}
TestClass(int i):pop(i){
std::cout<<"Param Constuctor\n";
}
TestClass &operator=(const TestClass &other){
std::cout<<"Assignment Operator \n";
return *this;
}
friend std::ostream &operator<<(std::ostream &out, TestClass &x);
};
std::ostream &operator<<(std::ostream &out, TestClass &x){
out<<" This is the TestClass with pop=" << x.pop <<"\n";
return out;
}
int main()
{
TestClass P0(333);
TestClass P_foo(555);
P_foo = P0;
std::cout << P0;
std::cout << P_foo;
return 0;
}
The result of this program is
Param Constuctor
Param Constuctor
Assignment Operator
This is the TestClass with pop=333
This is the TestClass with pop=555
So P_foo object preserves the initialized value 555.
If I comment out my custom assignment operator, the program works as expected.
Param Constuctor
Param Constuctor
This is the TestClass with pop=333
This is the TestClass with pop=333
What's wrong with my assignment operator function?

What's wrong with my assignment operator function?
At no point does *this get modified in your implementation of operator=:
TestClass &operator=(const TestClass &other){
std::cout<<"Assignment Operator \n";
return *this;
}

I see several issues with this code:
pop is not being initialized in the default constructor (which you are not calling, but you should still implement it properly, if you are going to implement it manually at all).
operator= is not updating the value of this->pop at all, which is the root cause of your issue. If you declare operator=, you are responsible for implementing it properly yourself, the compiler will not help you at all. But if you do not declare operator=, the compiler will auto-generate a default implementation that will assign a copy of the pop value for you.
operator<< should be taking the TestClass parameter by const reference.
Try this:
#include <iostream>
class TestClass{
private:
int pop;
public:
TestClass() : pop(0) { // <-- add this value!
std::cout << "Default Constructor\n";
}
TestClass(int i) : pop(i) {
std::cout << "Param Constructor\n";
}
TestClass& operator=(const TestClass &other){
std::cout << "Assignment Operator\n";
pop = other.pop; // <-- add this!
return *this;
}
friend std::ostream& operator<<(std::ostream &out, const TestClass &x);
};
std::ostream& operator<<(std::ostream &out, const TestClass &x){
out << " This is the TestClass with pop=" << x.pop << "\n";
return out;
}
int main()
{
TestClass P0(333);
TestClass P_foo(555);
P_foo = P0; // <-- this will work as expected now
std::cout << P0;
std::cout << P_foo;
return 0;
}

TestClass &operator=(const TestClass &other){
std::cout << "Assignment Operator \n";
pop = other.pop; // You need to add this
return *this;
}

The issue is that the assignment operator you defined doesn't assign anything to the instance it is called on.
Read through your operator again:
TestClass &operator=(const TestClass &other){
std::cout<<"Assignment Operator \n";
return *this;
}
You can see that two things happen. Assignment Operator is printed, and *this is returned. But your "other" TestClass is not used at all, and the data in this is never modified.
You can fix that by assigning to this->pop like so:
TestClass &operator=(const TestClass &other){
std::cout<<"Assignment Operator \n";
pop = other.pop; // Now this->pop will be assigned a new value from other.pop
return *this;
}
Now when you assign P_foo = P0, P_foo is successfully assigned the pop value from P0.

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.

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

When is the internal operator being used and when the external

Let's say I have defined a class with an internal + operator and also an external + operator;
class MyClass {
public:
MyClass operator +();
};
MyClass operator +(const MyClass& a);
If in my main program I call
MyClass a;
MyClass b = +a;
What is being called, this (internal):
a.operator +()
or this (external)?:
operator +(a)
The same question for binary operators.
The member function is chosen: it can bind directly to the expression a, while the non-member function needs to convert MyClass to const MyClass before binding to the reference parameter. So calling the member involves a better conversion sequence, making that the best overload.
If you removed const from the non-member, or added const to the member, then both would be equally viable; you should get an error saying that the overload is ambiguous.
By fixing some ambiguities in the code, and doing some printing, the following code will give the answer Internal operator.
class MyClass {
public:
MyClass operator+() {
std::cout << "Internal operator." << std::endl;
return *this;
};
};
MyClass operator+(const MyClass& a) {
std::cout << "External operator" << std::endl;
return a;
}
int main() {
MyClass a, b;
b = +a;
return 0;
}
The internal operator is used because you cannot overload an operator with the same arguments once it already exists: you cannot define a + operator for strings that does something crazy because there already is one that concatenates them. That's the same case. You have a + operator defined inside the class, so the identical one( as function prototype ) becomes useless.
I did a little test myself:
#include <iostream>
#include "MyClass.h"
using namespace std;
MyClass operator +(const MyClass& a, const MyClass& b)
{ cout << "external" << endl; return a; }
int main() {
MyClass foo, bar;
foo + bar;
return 0;
}
class MyClass {
public:
MyClass operator+(const MyClass& a) { cout << "internal" << endl; return a; }
};
The output of the program was "internal".
My conclusion is that if there is an internal operator that fits the operation it will be the one taken. I can't see a way to make the external one to be taken if the internal fits better. But I must point out that I only did a little test and haven't learned somewhere that this is the 100% answer.

Initialization lists in constructor

I've heard that the advantage of using initialization lists in constructor would be that there will be no extra copies of class type objects. But what does it mean for the following code in class T constructor? If i comment the assignment and use initialization lists what would be the difference?
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;
class X {
public:
X(float f_x = 0, float f_y = 0):x(f_x), y(f_y) {}
~X() {}
X(const X& obj):x(obj.x), y(obj.y) {}
friend ostream& operator << (ostream &os, X &obj);
private:
float x;
float y;
};
ostream& operator << (ostream &os, X &obj)
{ os << "x = " << obj.x << " y = " << obj.y; return os;}
class T {
public:
T(X &obj) : x(obj) { /* x = obj */ }
~T() { }
friend ostream& operator << (ostream &os, T &obj);
private:
X x;
};
ostream& operator << (ostream &os, T &obj)
{ os << obj.x; return os; }
int main()
{
X temp_x(4.6f, 6.5f);
T t(temp_x);
cout << t << endl;
}
It's exactly what you already said. If you don't use the initializer list, then the default constructor will get called first, and then the assignment operator will get called.
In your example, this is relatively benign (the compiler may even optimise this, I think). But in other cases, it's simply not possible to avoid the initializer list. Imagine if X didn't have a public assignment operator.
If you use Assignment, then:
x will be default constructed first &
then assigned with obj.
The cost is, Default Construction + Assignment
If you use Member initializer list then:
x will be constructed and initialized with obj.
The cost is, Construction only
T(X &obj) : x(obj) {}
will copy construct x from obj, while
T(X &obj){ x = obj; }
will construct a default x, only to then replace it with the values from obj.
If you intent to construct a member object, you should do it in the initialization list.