1

I'm trying to overload the binary + operator in C++. Now, I figured that it is wrong to return a reference to an Object when overloading operators because although the reference still exists when the method ends, the object will be deleted. So, this is wrong:

Vec& operator+(Vektor& a)
{
 Vec temp(*this);
 temp.x = this->x + a.x;
 temp.y = this->y + a.y;
 temp.z = this->z + a.z;
 return temp;
}

This would be correct:

Vec operator+(Vektor& a)
{
 Vec temp(*this);
 temp.x = this->x + a.x;
 temp.y = this->y + a.y;
 temp.z = this->z + a.z;
 return temp;
}

Now, my question is, if I actually use the upper version, why does the output of c work and the direct output of the result doesnt? I overloaded the << operator aswell. The second output results in gibberish, like 1.9492387e-12 or something. The first output (c) correctly gives me 2, 4 and 6.

Vec* a = new Vec(1, 2, 3);
Vec* b = new Vec(1, 2, 3);
Vec c = (*a + *b);
std::cout << c << std::endl << (*a + *b) << std::endl;

Any ideas? Here is the overloaded << operator:

friend std::ostream& operator<<(std::ostream& o, Vektor& a) {
 o << a.x << std::endl << a.y << std::endl << a.z << std::endl;
 return o;
}

Also, why do I return a reference to the streams here?

Thanks.

asked Feb 15, 2014 at 14:25
2
  • operator+ should be in terms of operator+=. And there's no need for a and b to be pointers. Commented Feb 15, 2014 at 14:33
  • There are also some typos like "Vek" and "Vektor" Commented Feb 15, 2014 at 15:10

2 Answers 2

1

This here is undefined behaviour:

Vec c = (*a + *b);

because the addition operator returns a reference to a defunct object. It may appear to work, but cannot be relied on. It is often said that when a program has undefined behaviour, literally anything can happen. This is an exaggeration, but the program can fail in unpredictable ways, and seem to work only sometimes. The bottom line is that it is wrong.

Concerning this

std::ostream& operator<<(std::ostream& o, Vektor& a)

the ostream is returned by reference such that you can chain it, for example

std::cout << Vektor(1, 2, 3) << " " << Vektor(4, 5, 6) << std::endl;

The returned reference is to the input parameter.

Note that there is absolutely no reason to use dynamic allocation here:

Vec* a = new Vec(1, 2, 3);

You can simplify things by saying

Vec a(1, 2, 3);
answered Feb 15, 2014 at 14:56
Sign up to request clarification or add additional context in comments.

Comments

0

In the first case

Vec& operator+(Vec& a)
{
 Vec temp(*this);
 temp.x = this->x + a.x;
 temp.y = this->y + a.y;
 temp.z = this->z + a.z;
 return temp;
}

you are creating a temporary object "temp" and returning its reference. There isn't much optimizations like RVO can do since you're explicitly asking for a reference to that specific object (they can't take place).. and after this function ends you'll have a reference to garbage. This is undefined behavior, you might still get right results but you might not. As for "why c works and the direct computation doesn't" it's not possible to know a priori, perhaps the direct computation has some sort of temporary value involved that immediately gets reused and thus you see garbage while the first does not.

In the second case, as you noted, you're asking for a copy of that object, and thus receiving a copy of that object which has the values copied in the right place.

I used the code below (C++11):

#include <iostream>
using namespace std;
class Vec {
public:
 Vec operator+(Vec& a)
 {
 Vec temp(*this);
 temp.x = this->x + a.x;
 temp.y = this->y + a.y;
 temp.z = this->z + a.z;
 return temp;
 }
 friend std::ostream& operator<<(std::ostream& o, Vec a) {
 o << a.x << std::endl << a.y << std::endl << a.z << std::endl;
 return o;
 }
 int x,y,z;
};
int main() {
 Vec* a = new Vec{1, 2, 3};
 Vec* b = new Vec{1, 2, 3};
 Vec c = (*a + *b);
 std::cout << c << std::endl << (*a + *b) << std::endl;
 return 0;
}

http://ideone.com/XANijy

Notice that the reference in the friend function to output the contents of the vector works because the object you're returning is the same you passed as parameter by reference and is fully functional (std::cout)

answered Feb 15, 2014 at 15:04

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.