Should I Return Const Objects

Should I return const objects?

Top level cv-qualifiers on return types of non class type are ignored.
Which means that even if you write:

int const foo();

The return type is int. If the return type is a reference, of course,
the const is no longer top level, and the distinction between:

int& operator[]( int index );

and

int const& operator[]( int index ) const;

is significant. (Note too that in function declarations, like the above,
any top level cv-qualifiers are also ignored.)

The distinction is also relevant for return values of class type: if you
return T const, then the caller cannot call non-const functions on the
returned value, e.g.:

class Test
{
public:
void f();
void g() const;
};

Test ff();
Test const gg();

ff().f(); // legal
ff().g(); // legal
gg().f(); // **illegal**
gg().g(); // legal

Purpose of returning by const value?

In the hypothetical situation where you could perform a potentially expensive non-const operation on an object, returning by const-value prevents you from accidentally calling this operation on a temporary. Imagine that + returned a non-const value, and you could write:

(a + b).expensive();

In the age of C++11, however, it is strongly advised to return values as non-const so that you can take full advantage of rvalue references, which only make sense on non-constant rvalues.

In summary, there is a rationale for this practice, but it is essentially obsolete.

Should I still return const objects in C++11?

Returning const objects is a workaround that might cause other problems. Since C++11, there is a better solution for the assignment issue: Reference Qualifiers for member functions. I try to explain it with some code:

int foo(); // function declaration
foo() = 42; // ERROR

The assignment in the second line results in a compile-time error for the builtin type int in both C and C++. Same for other builtin types. That's because the assignment operator for builtin types requires a non-const lvalue-reference on the left hand side. To put it in code, the assignment operator might look as follows (invalid code):

int& operator=(int& lhs, const int& rhs);

It was always possible in C++ to restrict parameters to lvalue references. However, that wasn't possible until C++11 for the implicit first parameter of member functions (*this).

That changed with C++11: Similar to const qualifiers for member functions, there are now reference qualifiers for member functions. The following code shows the usage on the copy and move operators (note the & after the parameter list):

struct Int
{
Int(const Int& rhs) = default;
Int(Int&& rhs) noexcept = default;
~Int() noexcept = default;
auto operator=(const Int& rhs) & -> Int& = default;
auto operator=(Int&& rhs) & noexcept -> Int& = default;
};

With this class declaration, the assignment expression in the following code fragment is invalid, whereas assigning to a local variable works - as it was in the first example.

Int bar();
Int baz();
bar() = baz(); // ERROR: no viable overloaded '='

So there is no need to return const objects. You can restrict the assigment operators to lvalue references, so that everything else still works as expected - in particular move operations.

See also:

  • What is "rvalue reference for *this"?

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

When should I return by T const&?

There are two reasons why you would prefer to return by const& rather than by value.

The first is semantics. A code which returns something by const& is telling the caller explicitly, "here is a read-only version of what you asked for. If you want to store it permanently, or make changes to it, you are responsible for making a copy of it." The semantics of this return type are quite clear, and easily enforced.

The second is optimization. By returning something by-value, you remove some optimization opportunities from the compiler. That is not to say that returning by-value is less efficient than returning by const& (in fact, in cases the opposite might be true -- consider a function that returns a char on a 64-bit system). It simply means you remove one of the tools from the compiler's optimization toolbox. There is another tool there to replace it -- namely, inlining the call along with copy elision -- so this might be a wash. It all depends on context.

I mention "semantics" as the first reason because I consider it to be the most important. There are so many variables with optimization and so many moving parts that it's often hard to know just what optimizations the compiler will be able to employ and when. One thing is certian all the time however -- clear semantics are more easily understood by humans than muddled semantics.

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.

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.

why sometime a function return a const, or const reference

There is not any good reason to return a const object. However, there are many good reasons to return pointers or references to const objects.

The program might have an object that is very expensive to copy, so it returns a reference. However, the object should not be changed through that reference. For example, it might be part of a sorted data structure and if its values were modified it would no longer be sorted correctly. So the const keeps it from being modified accidentally.

Arithmetic operator functions should not return const objects, because of exactly the problems in your question.

Dereferencing an iterator should return a const reference. That is if it is operating on a collection of const objects or possibly on a const collection. This is why class functions sometimes have two copies of a function with the second copy using a const on the function itself, like this:

T& operator[](size_t index);
const T& operator[](size_t index) const;

The first function would be used on non-const objects and the second function would be used for const objects.

what is the difference returning const or non-const in primative types c++

A const modifier on primitive return types will be ignored.

See also this question: Should I return const objects?



Related Topics



Leave a reply



Submit