Operator overloading returning a reference - c++

I am trying to understand what is the real deal with returning a reference, while studying operator overloading. I create this very simple problem:
#include <iostream>
using namespace std;
class mydoub {
public:
double pub;
mydoub(double i = 0) : pub(i) {}
};
mydoub &operator += (mydoub &a, double b) {
a.pub = a.pub+b;
return a;
}
int main() {
mydoub a(5), b(6);
cout << "1: " << a.pub << " " << b.pub << endl; // expected output 1: 5 6
b = a+= 7;
cout << "2: " << a.pub << " " << b.pub << endl; // expected output 2: 12 12
b.pub = 8;
cout << "3: " << a.pub << " " << b.pub << endl; // unexpected output: 3: 12 8
}
The output is:
1: 5 6
2: 12 12
3: 12 8
which is quite unexpected to me. In fact, b has been assigned a reference to a, right after the latter has been modified, so I expect b.pub=8 to act on a as well, as a result of the reference passing through the operator +=. Why isn't it so? What is then the difference with a non-reference overload, say mydoub operator += ( ..?

You are messing with an understanding of reference. Reference, in fact, is just dereferenced pointer and when you do b = a, it is actually copying the a value to b, they are not pointing to the same object. To point to the same object you need to use pointers or make b not mydoub type, but mydoub& type (in that case, while initializing you can point to the same object).
mydoub& operator += is used to can modify the result of += operator. For example,
mydoub a = 1;
++(a += 3)
After that a will 5, but if you use mydoub operator += it will be 4.

Related

Difference between passing an arguement

Hi All I have written two codes
1.
#include<iostream>
using namespace std;
void swap(int *x, int *y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
int main()
{
int a = 10, b = 20;
cout << "value of a before swap " << a << endl;
cout << "value of b before swap " << b << endl;
swap(&a, &b);
cout << "value of a after swap " << a << endl;
cout << "value of b after swap " << b << endl;
cin.get();
}
2.
#include<iostream>
using namespace std;
void swap(int *x, int *y)
{
int t;
t = *x;
*x = *y;
*y = t;
}
int main()
{
int a = 10, b = 20;
cout << "value of a before swap " << a << endl;
cout << "value of b before swap " << b << endl;
swap(a, b);
cout << "value of a after swap " << a << endl;
cout << "value of b after swap " << b << endl;
cin.get();
}
In both cases I am getting same output as
value of a before swap 10
value of b before swap 20
value of a after swap 20
value of b after swap 10
My First question is
Does swap(&a,&b) and swap(a,b) makes no difference to swap function??
But when i give same arguments to given below swap function
void swap(int &x, int &y)
{
int t;
t = x;
x = y;
y = t;
}
swap(a,b) gives no issue and work fine but when i pass value as swap(&a,&b) code gives Error
error C2665: 'swap': none of the 3 overloads could convert all the argument types
Why??
The problem is this evil line:
using namespace std;
In your second example, you're actually calling ::std::swap. Since your version of swap takes pointers, you must use the & operator.
See Why is “using namespace std;” considered bad practice?
In the first program there is called your own swap function for pointers.
In the second program there is called the standard function std::swap for objects of the type int due to unqualified name-lookup and presence of the using directive.
In the third program (when you supplied a and b) there is called your own function swap that accepts objects of the type int by reference. The compiler prefers to use a non-template function if both template and non-template functions are suitable.
But your swap function in the fourth program is not designed to swap pointers. So the compiler tries to select a standard swap function std::swap. But it is not designed to swap temporary (rvalues) objects. So the compiler issues an error.
You could call the standard swap function if you introduced intermediate variables that will contain pointers to variables a and b.
Here is a demonstrative program.
#include<iostream>
using namespace std;
void swap(int &x, int &y)
{
int t;
t = x;
x = y;
y = t;
}
int main()
{
int a = 10, b = 20;
int *pa = &a;
int *pb = &b;
cout << "value of *pa before swap " << *pa << endl;
cout << "value of *pb before swap " << *pb << endl;
swap( pa, pb);
cout << "value of *pa after swap " << *pa << endl;
cout << "value of (pb after swap " << *pb << endl;
cin.get();
}
Its output is
value of *pa before swap 10
value of *pb before swap 20
value of *pa after swap 20
value of (pb after swap 10
In this program your own function swap is not called because its parameters are references to objects of the type int but you are calling swap passing objects (pointers) of the type int *.
So the standard function std::swap specialized for objects of the type int * is called.
It swaps the pointers themselves not the objects pointed to by the pointers..
There is definitly a difference between 1 and 2
You are taking the address of actually reserved memory devoted to ( holding ) your variables a and that is OK, you can effectively swap their content.
You are considering the value of a and b to be a valid address but what I can assure you is that no OS gives you acces of those paricular zones in normal use so the address is wrong and the programs ends with a SEGFAULT and that is NOK.

Parameterized constructor for assignment

I've noticed some behaviour which I can't understand in parameterized constructors. Given the following program:
#include <iostream>
using namespace std;
class A {
public:
int x;
A() {}
A(int i) : x(i){
cout << "A\n";
}
~A(){
cout << "dA\n";
}
};
int main(){
A p;
p = 3;
cout << p.x << endl;
p = 5;
cout << p.x << endl;
return 0;
}
I get as output:
A
dA
3
A
dA
5
dA
This means that using = triggers the parameterized constructor, destroys the object on which it's called and creates a new object.
I cannot understand this behaviour and I can't find the answer in the standard ( I am sure it is there somewhere, but it may be stated in a sophisticated way). Could someone help me with an explanation?
The phrase you're probably looking for is "implicit conversion".
If you add a copy constructor and an assignment operator, and then give each object a unique ID, it's easier to see where things go:
int counter = 0;
class A {
public:
int id;
A(): id(++counter) {cout << "A(): " << id << "\n";}
A(int i) : id(++counter) {cout << "A(" << i << "): " << id << "\n";}
// Don't copy the id.
// (This isn't used anywhere, but you can't see that it's not used unless it exists.)
A(const A& a) : id(++counter) {cout << "A(" << a.id << "): " << id << "\n";}
// Don't copy the id here either.
A& operator=(const A&a) {cout << id << " = " << a.id << "\n"; return *this;}
~A(){cout << "destroy: " << id << "\n";}
};
int main(){
A p;
cout << "p is " << p.id << "\n";
p = 3;
cout << "p is " << p.id << "\n";
p = 5;
cout << p.id << "\n";
}
Output:
A(): 1
p is 1
A(3): 2
1 = 2
destroy: 2
p is 1
A(5): 3
1 = 3
destroy: 3
1
destroy: 1
As you can see, the parameterized constructor is used to create a temporary object whose value can be assigned to p, and that temporary is destroyed immediately after that.
You can also see that p is alive and well until the very end.
With a statement like
p = 3;
what you're actually doing is
p = A(3);
which really translates to
p.operator=(A(3));
The temporary A object created by A(3) of course needs to be destructed, it is temporary after all.
The object p itself will not be destructed by the assignment.

Precedence of postfix ++

Consider these codes:
int a = 5;
int b = a++;
cout << "b is " << b << endl; // b is 5
or:
int get_number(){
int a = 5;
return a++;
}
int main(){
int b = get_number();
cout << "b is " << b << endl; // b is 5
}
According to this table postfix ++ operator has higher precedence than = operator so the output should be b is 6. but the output is b is 5. How can we explain this?
The contract of the postfix++ operator (and postfix-- operator) for built-in types is that it returns the previous value, irrespective of the change that takes place. So the function still returns 5, even if the variable which received the change is assigned 6 afterwards.
As per expr.post.incr, emphasis mine:
The value of a postfix ++ expression is the value of its operand. [ Note: The value obtained is a copy of the original value — end note ]
The value computation of the ++ expression is sequenced before the
modification of the operand object. With respect to an
indeterminately-sequenced function call, the operation of postfix ++
is a single evaluation
int a = 5;
int b = a++; // the value computation for a is
// the non-modified / non-incremented value
// which is 5
std::cout << "a is " << a << std::endl; // a is 6
std::cout << "b is " << b << std::endl; // b is 5

C++ - Copy constructor with pointers as the data field

I have the following code :-
#include <iostream>
using namespace std;
class A {
int *val;
public:
A() { val = new int; *val = 0; }
int get() { return ++(*val); }
};
int main() {
A a,b = a;
A c,d = c;
cout << a.get() << b.get() ;
cout << endl ;
cout << c.get() << endl ;//
cout << d.get() << endl;
return 0;
}
It produces the output as :-
21
1
2
The behavior in case of c.get and d.get is easy to understand.
Both c and d share the same pointer val and a and b share the same pointer val.
So c.get() should return 1 and d.get() should return 2.
But I was expecting similar behavior in a.get() and b.get(). (maybe I have not understood cout properly)
I am unable to understand how a.get() is producing 2.
Can you explain why I am getting such an output. According to me the output should have been :-
12
1
2
cout << a.get() << b.get() ;
gets executed as:
cout.operator<<(a.get()).operator<<(b.get());
In this expression, whether a.get() gets called first or b.get() gets called first is not specified by the language. It is platform dependent.
You can separate them into two statements to make sure they get executed in an expected order.
cout << a.get();
cout << b.get();

When I return by value from an assignment operator, firstly what is the mechanism and basis of calling the copy constructor?

Consider this piece of code and its output:
class test {
int a, b;
public:
test (int a, int b) : a(a), b(b) { cout << "Const" << endl;}
test (const test & t) {
cout << "Copy constructor" << endl;
cout << "Being copied to = " << this << " from " << &t << endl;
if (&t == this) {
cout << "returning" << endl;
return;
}
this->a = t.a;
this->b = 6;//t.b;
}
test operator=(const test & in) {
cout << "Assignment operator" << endl;
this->a = in.a;
this->b = in.b;
cout << "Being written to = " << this << " from "<< &in << endl;
return *this;
}
test get () {
test l = test (3, 3);
cout << "Local return " << &l << endl;
return l;
}
void display () {
cout << a << " " << b << endl;
}
};
int main () {
int i = 5, &ref = i;
test t(1,1), u(2,2);
u = t.get();
cout << "u address" << &u <<endl;
//cout << "u ka = " << &u << endl;
u.display();
}
Output:
Const
Const
Const
Local return 0x7fff680e5ab0
Assignment operator
Being written to = 0x7fff680e5a90 from 0x7fff680e5ab0
Copy constructor
Being copied to = 0x7fff680e5a80 from 0x7fff680e5a90
u address0x7fff680e5a90
3 3
I know the way to return from an assignment is by reference, but I was trying to understand how this works since I am a beginner to C++.
What is the address 0x7fff680e5a80 ? Where is this coming from ? Which object is calling the copy constructor here ? I would expect u (address 0x7fff680e5a90) to call it.
Lets follow your code (I modified your constructor to dump the constructed this).
First you isntantiate t and u.
Const at 0x7fffffffdeb0
Const at 0x7fffffffdea0
Then you call t.get, which initializes l.
Const at 0x7fffffffdec0
You then return l.
Local return 0x7fffffffdec0
The copy constructor that would normally happen at this point is elided.
Assignment operator from l to u
Being written to = 0x7fffffffdea0 from 0x7fffffffdec0
Then you are returning the assignment by value (you should return it by reference), so you copy from u to an output value that isn't stored (0x7fffffffde90 from u)
Copy constructor
Being copied to = 0x7fffffffde90 from 0x7fffffffdea0
And then you print u.
u address0x7fffffffdea0
Inside T.
To get rid of the confusing (and unessisary copy) you should return by reference when you do any assignment operator:
test& operator=(const test & in);
Your assignment operator is incorrect:
test operator=(const test & in) {
You should return by reference:
test &operator=(const test & in) {
The object at 0x7fff680e5a80 is a prvalue temporary object of type test that is returned from your (incorrect) assignment operator and immediately discarded:
test operator=(const test & in) {
cout << "Assignment operator" << endl;
this->a = in.a;
this->b = in.b;
cout << "Being written to = " << this << " from "<< &in << endl;
return *this;
} // ^-- copy constructor is called here
You can check this by taking an rvalue reference to the return value of the assignment operator:
auto &&temp = (u = t.get());
std::cout << "Address of temp: " << &temp << std::endl; // prints 0x7fffffffde90