What Does It Mean to Return a Reference

What does it mean to return a reference?

It means you return by reference, which is, at least in this case, probably not desired. It basically means the returned value is an alias to whatever you returned from the function. Unless it's a persistent object it's illegal.

For example:

int& foo () {
static int x = 0;
return x;
}

//...
int main()
{
foo() = 2;
cout << foo();
}

would be legal and print out 2, because foo() = 2 modifies the actual value returned by foo.

However:

int& doit () {
int x = 0;
return x;
}

would be illegal (well, accessing the returned value would), because x is destroyed when the method exits, so you'd be left with a dangling reference.

Returning by reference isn't common for free functions, but it is for methods returning members. For example, in the std, the operator [] for common containers return by reference. For example, accessing a vector's elements with [i] returns an actual reference to that element, so v[i] = x actually changes that element.

Also, I hope that "is essentially equal to this code" means that they're semantically sort of (but not really) similar. Nothing more.

Is the practice of returning a C++ reference variable evil?

In general, returning a reference is perfectly normal and happens all the time.

If you mean:

int& getInt() {
int i;
return i; // DON'T DO THIS.
}

That is all sorts of evil. The stack-allocated i will go away and you are referring to nothing. This is also evil:

int& getInt() {
int* i = new int;
return *i; // DON'T DO THIS.
}

Because now the client has to eventually do the strange:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt; // must delete...totally weird and evil

int oops = getInt();
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

Note that rvalue references are still just references, so all the evil applications remain the same.

If you want to allocate something that lives beyond the scope of the function, use a smart pointer (or in general, a container):

std::unique_ptr<int> getInt() {
return std::make_unique<int>(0);
}

And now the client stores a smart pointer:

std::unique_ptr<int> x = getInt();

References are also okay for accessing things where you know the lifetime is being kept open on a higher-level, e.g.:

struct immutableint {
immutableint(int i) : i_(i) {}

const int& get() const { return i_; }
private:
int i_;
};

Here we know it's okay to return a reference to i_ because whatever is calling us manages the lifetime of the class instance, so i_ will live at least that long.

And of course, there's nothing wrong with just:

int getInt() {
return 0;
}

If the lifetime should be left up to the caller, and you're just computing the value.

Summary: it's okay to return a reference if the lifetime of the object won't end after the call.

when does a function have to return a reference in c++

References are used to provide assignment to return values of functions. Sounds odd, but as an example, the array assignment operator in c++ is a function that actually returns a reference to the element at the index parameter so that it can be assigned to, e.g.

class Array {
public:
int& operator[] (const int& index);
...
};

Allowing the following syntax:

Array a;
a[4] = 192;

Inspired by the eternally helpful C++ FAQ:

https://isocpp.org/wiki/faq/references#returning-refs

Why does return *this return a reference?

A function returns a reference if its declaration (i.e. its signature) tells so.

So (assuming a class Foo) if a function is declarated

 Foo fun();

then it returns a value (with copying, etc..)

But if it is declared as

 Foo& fun();

or as

 const Foo& fun();

a reference is returned.

The statement return *this; don't define by itself if a reference or a value is returned.

What does 'return *this' mean in C++?

this means pointer to the object, so *this is an object. So you are returning an object ie, *this returns a reference to the object.

What happens when you return a reference from a c++ function?

Well, I compiled your code with g++ version 5.4.0.

So I've been wondering:

  1. Why are we not getting a compilation error returning a reference to a non existent object?

The compiler doesn't give an error, but it does give you a warning.

sampe.cpp: In function ‘int& func(int)’:
sampe.cpp:6:15: warning: reference to local variable ‘num’ returned [-Wreturn-local-addr]
int& func(int num)
^

Also, you are not returning a reference to a non-existent object. When you are returning the reference, the object (or rather int) is present and not out-of-scope. Once the return statement is executed, then it goes out-of-scope.

That's why the compiler compiles the code and just gives a warning.


  1. What is this that is assigned to num2?

  1. Why does it not cause any execution errors, but just stops the program?

Now, when I execute the program, I get Segmentation fault, every single time (without any output). A quick use of gdb tells me that the line

int num2(func(num1));

in main() is the culprit. It's where my program crashes.

====================================================

TLDR;

As stated in comments to your question and the answer by @Hi - love SO, it's clear that there's nothing wrong with returning a reference to a local variable.

May be you are just using an old compiler which is somehow able to give you output as your program is entering the Undefined behaviour territory.

Which are the implications of return a value as constant, reference and constant reference in C++?

Here's the lowdown on all your cases:

• Return by reference: The function call can be used as the left hand side of an assignment. e.g. using operator overloading, if you have operator[] overloaded, you can say something like

a[i] = 7;

(when returning by reference you need to ensure that the object you return is available after the return: you should not return a reference to a local or a temporary)

• Return as constant value: Prevents the function from being used on the left side of an assignment expression. Consider the overloaded operator+. One could write something like:

a + b = c; // This isn't right

Having the return type of operator+ as "const SomeType" allows the return by value and at the same time prevents the expression from being used on the left side of an assignment.

Return as constant value also allows one to prevent typos like these:

if (someFunction() = 2)

when you meant

if (someFunction() == 2)

If someFunction() is declared as

const int someFunction()

then the if() typo above would be caught by the compiler.

• Return as constant reference: This function call cannot appear on the left hand side of an assignment, and you want to avoid making a copy (returning by value). E.g. let's say we have a class Student and we'd like to provide an accessor id() to get the ID of the student:

class Student
{
std::string id_;

public:

const std::string& id() const;
};

const std::string& Student::id()
{
return id_;
}

Consider the id() accessor. This should be declared const to guarantee that the id() member function will not modify the state of the object. Now, consider the return type. If the return type were string& then one could write something like:

Student s;
s.id() = "newId";

which isn't what we want.

We could have returned by value, but in this case returning by reference is more efficient. Making the return type a const string& additionally prevents the id from being modified.

C++: what is the advantage of references in this case?

Consider a simple class that wraps an array solely for the purpose of providing an example of what the OP can do with a returned reference.

class example
{
private:
int array[]= {1,2,3,4,5,6,7,8,9,0};
public:
int get(int index)
{
return array[index];
}
int & get2(int index)
{
return array[index];
}
}

Now we have an example that will not go into the badlands of undefined behaviour and can show you the power of this fully armed and operational reference.

Say we have

example x;

We can call either get function to retrieve a value

int val1 = x.get(1);
int val2 = x.get2(2)

but we can also

x.get2(3) = 30;

because get2 returns a reference we can assign to it and make the assignment stick.

This is invaluable should you want to add an index operator to example

int & operator[](int index)
{
return array[index];
}

because it allows the expected array behaviour

int val = x[5];
x[6] = 10;

EDIT

Tony D brings up another important feature. Returning a reference returns by reference. In addition to allowing modification of the returned object, this does not make a copy and saves whatever effort would have been consumed by making a copy. For the example case of integers this is moot. The cost of passing an integer and a reference to an integer will either be the same or so close that it shouldn't matter. This is not true of a larger, more complex object that could take a significant amount of effort to copy or an object that cannot or should not be copied.

BigFreakingObject & getBigFreakingObject();

will allow the caller to operate on a BigFreakingObject without incurring the costs of duplicating it. This hands over the keys to the kingdom however and allows the caller to do to BigFreakingObject whatever BigFreakingObject's permissions will allow, and this may conflict with the requirements of BigFreakingObject's owner.

Declaring the reference as const with

const BigFreakingObject & getBigFreakingObject();

or

BigFreakingObject const & getBigFreakingObject();

will provide a reference to a BigFreakingObject but not allow the caller to modify its state, protecting the owner of BigFreakingObject from any unpleasant surprises.

For more details on this, read up on Const Correctness.

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.



Related Topics



Leave a reply



Submit