C++ Return Value, Reference, Const Reference

C++ Return value, reference, const reference

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.

When is it a good idea to return a const reference in C++?

The decision of when to return by-reference vs. by-value is not just a matter of performance, it's a matter of code semantics (although performance usually matters a lot when coding in C++).

Some notable examples of returning by-reference are:

  • a getter is often expected to return a const-reference to the actual member, unless that member is cheap to copy
  • to allow for method or operator chaining, returning a reference to the current object (*this)

The question of when to return by-reference actually boils down to a broader question of how to manage an object's lifetime safely. C++ Core Guidelines on object's lifetimes is a good resource to adhere to.

If the object being referred-to outlives the function invocation, then it's generally safe to return it by-reference.

So:

  • this, class members and objects with static storage duration: safe to return it by-reference
  • locals and function's input arguments: not safe to return by-reference

Regarding input arguments - it applies even to const references, since they can refer to temporaries. For example:

std::string const& badFunc(std::string const& arg) {
return arg; // not a good idea
}

std::string const& x = badFunc("abc");
// now x contains a dangling reference

C++: What does a const reference to the return value of a function mean?

Your code:

const std::string &file_name = it->path().string();

extends the lifetime of the temporary std::string returned by std::filesystem::path::string(). Since you've marked that as const, it can't be moved into file_names, it must be copied. Assuming you want a move, you would write:

auto&& file_name = // ...
file_names.push(std::move(file_name));

Notice that std::queue has a push() overload for r-value references.

Modern C++ provides a lot of opportunities for compilers to optimize, so avoiding questions/"confusion" about dangling references (the auto&& syntax is "new" in C++11) might be a better approach:

auto file_name = // ...
file_names.push(std::move(file_name));

Writing "natural" code that "looks and behaves like the ints" is often a good approach. In the unlikely situation you find that this is really a performance bottleneck, you can revisit; write your code for clarity first.

Returning const reference

string("foo") creates an object of type std::string containing the value "foo" locally in the function. This object will be destroyed at the end of the function. So returning the reference to that object will be invalid once the code leaves that function [1]. So in main, you will never have a valid reference to that string. The same would be true if you created a local variable inside foo.

The WHOLE point of returning a reference is that you don't make a copy, and initializing a reference (string &f = foo() is an initialization) will not create a copy of the original object - just another reference to the same object [which is already invalid by the time the code is back in main]. For many things, references can be seen as "a different name for the same thing".

The lifetime of the referred object (in other words, the actual object the "alias name" refers to) should ALWAYS have a lifetime longer than the reference variable (f in this case).

In the case of bar, the code will make a copy as part of the return string("bar");, since you are returning that object without taking its reference - in other words, by copying the object, so that works.

[1] pedantically, while still inside the function, but after the end of the code you have written within the function, in the bit of code the compiler introduced to deal with the destruction of objects created in the function.

C++ return by reference and return by const-reference value is copied

The variable returned gets a copy, not a reference, why?

When you use a reference to initialize a value whose type is not a reference you get a copy, for example

#include <cassert>

int main() {
int a = 1;
const int& a_ref = a;
int b = a_ref;
assert(&b != &a);
}

Does the const std::set<uint32_t> & GetValues () const function must contain the double const

The second const is applied as a member function qualifier, it means that the method can be called when the calling instance of your class is const qualified. For example

Test test;
test.GetValues(); // 1
const Test& test_ref = test;
test_ref.GetValues(); // 2

Here 1 will call the non-const version and 2 will call the method qualified with const

Further a const qualified method will not let you return non-const references to it's own values, so you must return a const reference to your member variable m_values.

So if you include the second const then you must include the first const, however if you just make the return type be a const reference then you don't need to make the method const. For example

const std::set<uint32_t>& GetValues() // 1
std::set<uint32_t>& GetValues() { return m_values; } // 2

here 1 is allowed but 2 is not allowed.

The reason this happens if you are curious, is because the implicit this pointer is const qualified to be a pointer to const in const qualified methods.


In order to call the size () function (or any other member of the returned object), is a copy created temporarily or all is resolved with the returned reference?

The size() method will be called on the reference! The best way to test things like this is to try it out in a quick test case https://wandbox.org/permlink/KGSOXDkQESc8ENPW (note that I have made the test a little more complicated than needed just for demonstration)

Is it bad to have three functions, return by value, by const-reference and by reference?

If you are exposing the user to a mutable reference, then the best way to let them make a copy (which is why you had the by-value) method is to let them make a copy themselves by initializing a non-ref qualified set with the returned reference (like you did initially)

Also in your code there is am ambiguity between the following two methods

std::set<uint32_t> GetValues() const
const std::set<uint32_t>& GetValues () const

Because all that is different is the return type, and you cannot overload a function off the return type.

C++ Get result of function returning by value in const reference

const A& a = getFoo();

Is it a bad approach ? Should it be ?

const A a = getFoo();

Former introduces unnecessary indirection and gives no benefit as far as I can tell. Latter is simpler to understand (no need to know about lifetime extension of temporaries bound by references) which makes it better.

return const reference vs temporary object

Even if you assign it to a const reference, the return value is declared as passed by value, that means it'll be copied[1] to outside as a temporary object, and then binded to the const reference. Binding temporary object to a const reference is fine, the object won't be destroyed until getting out of the lifetime of the const reference.

On the other hand, returning reference of a local variable is illegel. The local variable'll be destroyed when the function returned, that means the outside reference will be dangled.

EDIT

My point is that if assigning a const ref to a returned local variable is legal, then shouldn't assigning a const ref to a returned const ref of a local variable be legal as well?

The point is the 1st case is not assigning a const ref to a returned local variable, it's assigning a const ref to a returned temporary variable. (Which might copied from the local variable.)


[1] The copy might be omitted according to RVO technically.

In which cases is it unsafe to (const) reference a return value?

Which side-effects could lead to the invalidation?

Holding a reference to the internal state of a class (i.e., versus extending the lifetime of a temporary) and then calling any non-const member functions may potentially invalidate the reference.

Is it bad-practice to assign return values to a const reference? (Especially when I don't know the interior of the function)

I would say the bad practice is to hold a reference to the internal state of a class instance, mutating the class instance, and continuing to use the original reference (unless it is documented that the non-const functions don't invalidate the reference)



Related Topics



Leave a reply



Submit