C++ Return value, reference, const reference
Asked Answered
C

5

91

Can you explain to me the difference between returning value, reference to value, and const reference to value?

Value:

Vector2D operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

Not-const reference:

Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

Const reference:

const Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

What is the benefit of this? I understand the sense behind const reference passing to function as you want to make sure not to modify this value on which reference is pointing to inside a the function. But I'm confused by the meaning of returning const reference. Why returning of reference is better than returning of value, and why returning of const reference is better than returning of not-const reference?

Collyrium answered 14/2, 2014 at 11:23 Comment(1)
One Benifit of Returning by Non-Const Reference from Operators is Operator Chaining.Deni
M
50

There is no difference unless you write something weird like

(v1 += v2) = v3;

In the first case, the assignment will be to a temporary, and the overall effect will be v1 += v2.

In the second case, the assignment will be to v1, so the overall effect will be v1 = v3.

In the third case, the assignment won't be allowed. This is probably the best option, since such weirdness is almost certainly a mistake.

Why returning of reference is better than returning of value?

It's potentially more efficient: you don't have to make a copy of the object.

and why returning of const reference is better than returning of not-const reference?

You prevent weirdness like the above example, while still allowing less weird chaining such as

v1 = (v2 += v3);

But, as noted in the comments, it means that your type doesn't support the same forms of (ab)use as the built-in types, which some people consider desirable.

Megacycle answered 14/2, 2014 at 11:26 Comment(7)
I think it's debatable whether const is better than non-const, you cannot call a method that is non-const on the result of +=. What about (v1 += v2).non_const_fun();. I know it is opinion, and I give that it may look a bit weird, but it does make more sense than (v1+=v2)=v3. Is there really a point in forbidding it?Superorganic
@Superorganic I can see a lot of logic in forbidding it, but... the built-in += returns a modifiable lvalue, and returning a non-const reference is the closest thing to that in a user defined type. So the principle of least surprise---user defined operators should emulate the built-in ones---says non-const reference.Vitrine
However, const& prevents v1 = std::move(v2 += v3) from actually moving. Not sure if that's interesting or not.Tarnation
Indeed, there are varied opinions on what kind of multi-effect expressions should be allowed. I'd probably return void, to prevent any surprises, unless there was a particular requirement to allow obfuscation.Megacycle
@JamesKanze That's really nicely worded point I tried to make in my answer. Such syntax as this mock-up example (v1+=v2)=v3 is expected to work. Well at least, I would expect it to work since it would work for the built-in types. I just wonder of a reason why to forbid it. Is it only to potentially catch "stupid" errors?Superorganic
Just to be clear, I think it is a very good point, that you can change expected/allowed syntax. It might be worth it. I consider it a "trade off". I asked for opinion because you (all commenters here) have far superior experience than I do.Superorganic
@Superorganic (v1 += v2) = v3 would be undefined behavior for a built in type (at least pre-C++11---I'm not sure now). The motivation (so I've been told, by people who definitely know) is to support things like int& func() { ... return x += y; } (Assuming that x has sufficient lifetime.) I'm not convinced, and I would regularly use two statements there, as well. But others seem to have (or at least to have had) a different opinion.Vitrine
F
24

Value:

Returning by value means that you are returning a copy of an object. This puts requirements on the class (it has to be copyable or moveable). This means that for object of some classes returning by value may be expensive (in a case where RVO or NRVO does not work or is switched off). This also means that the new object is independent (subject to its design) from other objects and is a value of its own. This is what you probably should return from many binary operators like +, -, * and so on.

Non-const reference:

You really return an alias for another object. The alias being non const allow you to modify aliased object. This is what you should return from some unary oprators like prefix ++ and --, and * (dereference) as you usually want to have the ability to modify returned object.

This is returned by operator>> and operator<< overloaded for streams. This allows chaining of operators:

cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;

You can also return reference to *this when you want to allow chaining of regular methods like this:

object.run().printLastRunStatistics();

Const reference:

Like above but you CANNOT modify aliased object. May be used instead of returning by value when the object to be returned is expensive to copy and when you can ensure its existence after you return from a function.

This is what operator= usually returns to allow multiple assignments in a way standard types support them:

a = b = c;

Const-reference used in operator= prevents this kind of usage (not supported by standard type as far as I remember):

++(a = b);

which would be allowed if normal reference was used.

Fraternal answered 14/2, 2014 at 11:44 Comment(0)
C
15

The difference between return-by-value and return-by-reference takes effect during run-time:

When you return an object by-value, the copy-constructor is called, and a temporary instance is created on the stack.

When you return an object by-reference, all the above does not take place, leading to improved performance.


The difference between return-by-reference and return-by-constant-reference has no run-time effect, and is simply there to protect you from writing erroneous code.

For example, with Vector2D& operator += (const Vector2D& vector), you can do:

(x+=y)++ or (x+=y).func() where func is a non-const function in class Vector2D.

But with const Vector2D& operator += (const Vector2D& vector), the compiler will generate an error for any such similar attempt.

Cuenca answered 14/2, 2014 at 11:36 Comment(0)
S
6

It is exactly the same as passing argument to the function.

You want to return a const reference when you return a property of an object, that you want not to be modified out-side of it. For example: when your object has a name, you can make following method const std::string& get_name(){ return name; };. Which is most optimal way. You allow a "read-only" access to an internal property, with out copy-on-return.

When you are overloading operators you are expected to return an object that is mutable, otherwise some certain syntax that is usually expected to work will produce errors. It is quite important when you try some weird chaining.

For example option 3 will not work with something like (v1 += v2).non_const_method(), While, the following would:

v1+=v2;
v1.non_const_method();
Superorganic answered 14/2, 2014 at 11:27 Comment(1)
Ok it wasn't clean for me. So "const" has effect directly for returning object, so we can't call cascade of functions on it. If we had assigned returned object to our new object, it isn't const anymore. Thanks to all of you!Collyrium
P
1

As pointed out but luk32 it is just to ensure that no changes are allowed to the objects returned by this function. This can basically help you in finding your logical errors at compile time. Suppose you are sure not to change a object, and your code is changing the object, it can be tracked. It can be thought of a good coding practice.

Papert answered 14/2, 2014 at 11:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.