The code below shows a class representing complex numbers. My interest is in understanding the operator+ function. As I understand Complex res should be allocated on the frame of the function operator+. Is it correct to return this object to the caller? By the time this function returns the frame would have been popped but res would continue to be used by the caller. Unless there is more to this than meets the eye, like the actual return res may actually be copying the object from current frame to the caller's frame. Another possibility can be that the code inside the operator+ function may be inlined on the call site in main? From my limited understanding of the language, functions declared within the class are by default inlined on the call site. Any help will be appreciated.
#include<iostream>
using namespace std;
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i =0) {real = r; imag = i;}
Complex operator+(Complex const &obj) {
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
void print() { cout << real << " + i" << imag << endl; }
};
int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2;
c3.print();
}
PORTION BELOW ADDED TO CLARIFY THE SOLUTION AFTER READING THE COMMENTS AND ANSWERS BELOW
I updated the code above with the following:
#include<iostream>
using namespace std;
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i =0) {real = r; imag = i;}
Complex operator+(Complex const &obj) {
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
cout << "Address inside the function " << &res << "\n";
return res;
}
void print() { cout << real << " + i" << imag << endl; }
};
int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2;
cout << "Address outside the function " << &c3 << "\n";
c3.print();
}
The output shows two different addresses on two different regions of the stack indicating copy by value during return:
Address inside the function 0x7fffbc955610
Address outside the function 0x7fffbc955650
Is it correct to return this object to the caller?
C++ supports both return by reference and return by value. Since you are not using return by reference, you are not returning a reference to the object to the caller. You are using return by value, so you are returning the object's value to the caller. Consider:
int foo()
{
int i = 2;
return i;
}
This returns the value 2. It does not return the object i. That i itself no longer exists after the return doesn't matter because its value has already been used to determine the value returned.
Transfer with value always uses stack.
When you want to return a value, depending on the caller code, the copy constructor or assignment operator may implicitly call and assign the return value to the object on the left. (lvalue)
Complex nwobj=cmpx1 + cmplx2; //copy constructor used to assign return object to lvalue
cmplx3=cmplx1+xmplx2;//operator= used to make a right assignment.
Note:
The copy construction in the first line may happen or may be elided depending on the used compiler and its settings. A comprehensive explanation about this can be found in:
SO: What are copy elision and return value optimization?
Related
#include "stdafx.h"
#include "iostream"
using namespace std;
class complex
{
int real;
int img;
public:
complex(int x = 0, int y = 0)
{
cout << "Inside Prama" << endl;
real = x;
img = y;
}
complex operator+(complex x)
{
complex temp;
temp.real=real + x.real;
temp.img=img + x.img;
return temp;
}
void display()
{
cout << real << ' ' << img << endl;
}
};
int main()
{
class complex c1(5,6), c2(7,8),c3(7,7),c4;
c1.display();
c2.display();
c3.display();
c4 = c1+c2+c3;
c4.display();
return 0;
}
for above operator overloading code following is the output:
why that parameterized constructor is called at the time of adding of the objects.I am not getting the reason for that
Just summarizing comments...
Here
complex operator+(complex x)
{
complex temp;
temp.real=real + x.real;
temp.img=img + x.img;
return temp;
}
complex temp; calls the constructor and thats the output you see. Typically you'd pass x as const reference to avoid the copy, but as you need a copy anyhow you can use x:
complex operator+(complex x)
{
x.real +=real;
x.img +=img;
return x;
}
This will only invoke the compiler generated copy constructor when you call the operator.
There are more subtleties to consider. Using x instead of making a local copy inhibits named return value optimization. Also it is common to implement operator+ in terms of operator+= and operator+ can be a free function then. Note that operator+= can be more efficient, because no copy is needed at all. For more details on operator overloading in general I refer you to What are the basic rules and idioms for operator overloading?
PS: "parametrized constructor" is a term I have seen only in poor misleading tutorials so far. It is not an official term. The relevant term here is default constructor. complex(int x = 0, int y = 0) is a default constructor because it can be called without parameters. It is a good example for why "parametrized constructor" does not convey lots of meaning and is rather misleading.
Please look at the following code and help me understand:
Why the functionality to return a const alias to a literal like my f2 function exists. I don't understand what the point is.
The difference between f2 and f3 is that const does allow me to put a literal in the return statement, but again why?
Any help in understanding this is appreciated.
#include <iostream>
const int f1(int a)
{
return 15;
}
const int& f2(int a)
{
return 14;
}
int& f3(int a)
{
a = 12;
return a;
}
int main()
{
auto a{ 10 };
auto b = f1(a);
auto c = f2(a);
auto d = f3(a);
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3;
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
Both f2 and f3 have undefined behaviour. You are returning references to local variables. Those local variables are destroyed when the function ends, and the reference is dangling.
The difference between a const reference, and a non-const reference is that a const reference can bind to both rvalues and lvalues.
For non-const references you have to distinguish between lvalue-reference(int&) and rvalue-reference(int&&).
So using the function signature int&& f2(int a) would also compile, but equally have undefined behaviour.
The main reason this is usefull is because when we pass a reference to a function, the function signature tell us if we are expecting an lvalue or an rvalue. We can also overload both and decide to move/copy depending on what we get.
In the case where we don't care, or if we only want to read from the value we can use a const reference and be able to accept both lvalues and rvalues that are passed in.
void foo(MyClass& mc) {
// We know mc is an lvalue.
// We could copy mc, or modify it if we want to use it as an output parameter.
}
void foo(MyClass&& mc) {
// We know mc is an rvalue.
// We know it would be safe to move from mc in this case.
}
MyClass mc;
foo(mc); // Callsthe first overload
foo(MyClass{}); // Calls the second overload
// The two functions above can be overloaded, so we can make sure we deal
// with both cases in the right way
void foo2(const MyClass& mc) {
// This can be both an rvalue or lvalue.
// We don't really care since the reference
// is const we are only going to read from it.
}
foo2(mc); // Both calls work
foo2(MyClass{});
The b, c and d variables in main are initialized with a copy of what the functions return. No matter if they return a copy, a ref or a const ref.
To keep the attributes of the returned value, let's change the first lines in main:
int main()
{
auto a{ 10 };
auto& b = f1(a); // Does not compile, a ref can't be tied to a r-value
auto& c = f2(a); // Ok, c's type is 'const int&'
auto& d = f3(a); // Ok, d's type is 'int&'
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3; // Does not compile. c is a ref to a const
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
So, the point is you can return a reference to an internal variable, but now allowing the caller to change it. Doing so (instead of returning a copy), you
avoid the copy
allow the caller to see any later change
Not much sense for the code above, but think of a method inside a class, where the internal variable can be changed in other ways.
Besides the return type, f2 and f3 are not correct, as they return a reference to a not-in-memory (f2) or temporary object (f3).
Let's say you write a function that needs to return a complex object, but this object shouldn't be modified (such as pointer to a shared resource, class-property, some sort a singleton data and so on).
For the sake of this answer, lets assume the type in "struct Point".
You have 2 options to do so:
return it by value, which will create a deep copy of its primitive type members and a shallow copy of its by-reference-types members:
const struct Point f2(...)
return it by reference, which will copy only the pointer to the object:
const struct Point* f2()
const struct Point& f2()
both are valid, while the second one has the advantage when dealing with heavy objects.
In the code you provided you do not see the difference because "int" is a primitive type which means it has known way to be copied. This means var "c" isn't actually an alias nor a const, its an int who took its value from the return type of f2
I want to have double values with a name and units, but I want to use them as if they were simple doubles. For example I want to use them like this:
int main(){
NamedValue a("a","m");
NamedValue b("b","m");
NamedValue c("c","m^2");
a = 3;
b = 5;
c = a*b;
std::cout << a << b << c << std::endl;
return 0;
}
and the output should be:
a = 3 m
b = 5 m
c = 15 m^2
I came up with this solution:
class NamedValue {
public:
NamedValue(std::string n,std::string u) : name(n),units(u){}
const std::string name;
const std::string units;
void operator=(double v){this->value = v;}
void operator=(const NamedValue& v){this->value = v.value;}
operator double() const { return value; }
private:
double value;
};
std::ostream& operator<<(std::ostream& stream,const NamedValue& v) {
stream << v.name << " = " << (double)v << " " << v.units << std::endl;
return stream;
}
Unitl now it works nicely, but I am mainly concerned about the assignment operator void operator=(const NamedValue& v){this->value = v.value;} that is not exactly doing, what one normally would expect of an assignment operator.
Are there any bad consequences that I will face?
I am thinking about things like passing an object as parameter and stuff like that. However, a function like this
NamedValue test(NamedValue x){return x;}
works without problems, as there is no assignment involved (only copy constructor). Am I missing something? Is there anything else I should be aware of?
ps: Just in case you wonder, at the moment I do not care about checking the units when doing calculations.
The assignment operator is totally fine. The only thing unusual about it is that you did not return the object so the operator calls cannot be chained. Otherwise, it's a completely normal operator.
What's the difference in usage of function get1() and get2()?
struct x
{
float get1() const
{
float fx = 4;
fx += 1.5f;
return fx;
}
float& get2() const
{
float fx = 4;
fx += 1.5f;
return fx;
}
};
int main()
{
x t;
float x1 = t.get1();
float/*&*/ x2 = t.get2();
cout << x1 << endl;
cout << x2 << endl;
cin.get();
}
As i understand, get2() can only be const class member..
It's not clear for me completely. If someone can point me to a reference or just a short but complete solution, would be nice.
In your case, get2() invokes undefined behavior because you return a reference to a method-local that goes out of scope.
The difference is that returning float returns a float value, while float & returns a reference to a float. The reference can be used to alter the data of the referent; when returning by value you just get a copy.
It sounds like you are just confused about what references do, so here is the colloquial definition: a reference is another name for an object. That means that a reference requires the existence of its target to exist elsewhere, very similar to a (non-null) pointer.
Let me write a better example to illustrate the difference:
struct x
{
x() : data(0) { }
float get1() const
{
return data;
}
// Cannot be const now, because we can't return a non-const reference to what
// would be a const data member. (If this method were const then data would be a
// const float, and that cannot bind to float &.)
float & get2()
{
return data;
}
private:
float data;
};
Now we have two methods, one that returns data and one that returns a reference to it. The difference here is that with get2() you can actually change the value of x::data:
x an_x;
float a = an_x.get1(); // a is 0
a = 5; // a is 5, an_x.data is still 0
a = x.get1(); // a is 0 again, because an_x.data did not change
float & b = an_x.get2(); // b is 0
b = 5; // b is 5, and so is an_x.data!
a = x.get1(); // a is now 5, because an_x.data is 5
Notably, returning a reference makes the result of the expression an lvalue:
an_x.get1() = 5; // Compile-time error, because a float is not an lvalue.
an_x.get2() = 5; // Compiles, and sets an_x.data to 5.
This is a technique used by the standard library containers; vector<int> for example returns int & from its non-const operator[] overload, which is why some_vector[0] = 5; compiles and works as you would expect.
float fx = 4;
In your case fx is local variable. It will die once you come out of function. If you are returning float then you are making copy of value, so even fx die, no problem. But if you are returning float&, you are returning reference to died variable. Which is undefined behaviour.
Copying is costly operation. When you return reference, you are not making actual copy, but you are returning address of varaiable. You should return reference if your variable will alive after returning from function. But in your case, fx will die once you come out of function.
I simulated your case in below blocks of code, you can compare the output of two case for making clearly. Hope it help.
#include <iostream>
class A
{
public:
A()
{
std::cout << this << ": A()\n";
}
A(const A&)
{
std::cout << this << ": Copy constructor\n";
}
~A()
{
std::cout << this << ": ~A()\n";
}
};
struct x
{
A get1() const
{
A a;
return a;
}
A &get2() const
{
A a;
return a;
}
};
int main(int argc, char *argv[])
{
x t;
/*{
t.get1();
}*/
{
t.get2();
}
std::cin.get();
}
I stumbled upon something similar today, and subsequently tried a few things out and noticed that the following seems to be legal in G++:
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) { val_ = val; return *this; }
int get() { return val_; }
};
struct B : public A {
A getA() { return (((A)*this) = 20); } // legal?
};
int main() {
A a = 10;
B b;
A c = b.getA();
}
So B::getB returns a type A, after it as assigned the value 20 to itself (via the overloaded A::operator=).
After a few tests, it seems that it returns the correct value (c.get would return 20 as one may expect).
So I'm wondering, is this undefined behavior? If this is the case, what exactly makes it so? If not, what would be the advantages of such code?
After careful examination, with the help of #Kerrek SB and #Aaron McDaid, the following:
return (((A)*this) = 20);
...is like shorthand (yet obscure) syntax for:
A a(*this);
return a.operator=(20);
...or even better:
return A(*this) = 20;
...and is therefore defined behavior.
There are a number of quite separate things going on here. The code is valid, however you have made an incorrect assumption in your question. You said
"B::getA returns [...] , after it as assigned the value 20 to itself"
(my emphasis) This is not correct. getA does not modify the object. To verify this, you can simply place const in the method signature. I'll then fully explain.
A getA() const {
cout << this << " in getA() now" << endl;
return (((A)*this) = 20);
}
So what is going on here? Looking at my sample code (I've copied my transcript to the end of this answer):
A a = 10;
This declares an A with the constructor. Pretty straightfoward. This next line:
B b; b.val_ = 15;
B doesn't have any constructors, so I have to write directly to its val_ member (inherited from A).
Before we consider the next line, A c = b.getA();, we must very carefully consider the simpler expression:
b.getA();
This does not modify b, although it might superfically look like it does.
At the end, my sample code prints out the b.val_ and you see that it equals 15 still. It has not changed to 20. c.val_ has changed to 20 of course.
Look inside getA and you see (((A)*this) = 20). Let's break this down:
this // a pointer to the the variable 'b' in main(). It's of type B*
*this // a reference to 'b'. Of type B&
(A)*this // this copies into a new object of type A.
It's worth pausing here. If this was (A&)*this, or even *((A*)this), then it would be a simpler line. But it's (A)*this and therefore this creates a new object of type A and copies the relevant slice from b into it.
(Extra: You might ask how it can copy the slice in. We have a B& reference and we wish to create a new A. By default, the compiler creates a copy constructor A :: A (const A&). The compiler can use this because a reference B& can be naturally cast to a const A&.)
In particular this != &((A)*this). This might be a surprise to you. (Extra: On the other hand this == &((A&)*this) usually (depending on whether there are virtual methods))
Now that we have this new object, we can look at
((A)*this) = 20
This puts the number into this new value. This statement does not affect this->val_.
It would be an error to change getA such that it returned A&. First off, the return value of operator= is const A&, and therefore you can't return it as a A&. But even if you had const A& as the return type, this would be a reference to a temporary local variable created inside getA. It is undefined to return such things.
Finally, we can see that c will take this copy that is returned by value from getA
A c = b.getA();
That is why the current code, where getA returns the copy by value, is safe and well-defined.
== The full program ==
#include <iostream>
using namespace std;
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) {
cout << this << " in operator= now" << endl; // prove the operator= happens on a different object (the copy)
val_ = val;
return *this;
}
int get() { return val_; }
};
struct B : public A {
A getA() const {
cout << this << " in getA() now" << endl; // the address of b
return (((A)*this) = 20);
// The preceding line does four things:
// 1. Take the current object, *this
// 2. Copy a slice of it into a new temporary object of type A
// 3. Assign 20 to this temporary copy
// 4. Return this by value
} // legal? Yes
};
int main() {
A a = 10;
B b; b.val_ = 15;
A c = b.getA();
cout << b.get() << endl; // expect 15
cout << c.get() << endl; // expect 20
B* b2 = &b;
A a2 = *b2;
cout << b2->get() << endl; // expect 15
cout << a2.get() << endl; // expect 15
}