5

I have read that we should not return a pointer or a reference to a local variable. So in the below given example, i understand that when i wrote: return i; inside function foo, i am returning a reference to a local variable. And using that reference outside the function, will lead to undefined behavior.

#include <iostream>

const int& foo()
{
    int i = 5;
    return i;//returning reference to a local variable
}

const int& func()
{
    return 5;
}

int main()
{
    const int& ref = func();
    const int& f = foo();
    std::cout<<f<<std::endl; //I know this is undefined behavior because we're using a reference that points to a local variable 
    std::cout<<ref; //But IS THIS UNDEFINED BEHAVIOR too?
}

My question is that does the same hold true for the return statement return 5; inside function func. I am aware that in C++17 there is mandatory copy elison. So my question is directed towards all modern C++ version(C++11, C++17, etc). Does the behavior depends/differs on C++ version.

In particular, i know that the statement std::cout<<f<<std::endl; inside main is always undefined behavior because we're using a reference(dangling) that points to a local variable. But does the statement std::cout<<ref; also leads to undefined behavior. If not why and what will happen here.

PS: I might be wrong in describing what is actually happening in the first cout statement too. So please correct me if i am wrong.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • @463035818_is_not_a_number You said: *"returning a reference to a local variable is always UB"*. Is returning a reference to a local variable always UB or actually **using** that returned value actually constitutes UB? – Jason Mar 31 '22 at 13:50
  • I believe the return value optimization only applies when the return statement is, in fact, returning _by value_, so it doesn't apply to a function returning a `const int&` instead of an `int` in the first place. I'm not sure whether temporary lifetime extension applies to either of these cases since you're binding to a `const` ref. – Nathan Pierson Mar 31 '22 at 13:50
  • Clang gives, for your `func`,: *warning : returning reference to local temporary object [-Wreturn-stack-address]*. And the output is garbage. – Adrian Mole Mar 31 '22 at 14:05
  • Back in the olden days, some FORTRAN implementations stored literal constants in ordinary memory. So you could write the FORTRAN equivalent of `func() = 6; std::cout << 5 << '\n';` and the program would display the value 6 because the assignment to `func()` changed the value of the literal 5. – Pete Becker Mar 31 '22 at 14:14

1 Answers1

2

Is returning a reference to a local int variable always undefined behavior

Technically no. Returning a reference to a local variable (regardless of type) is never undefined behaviour itself. But such returned reference will always be invalid (if the variable is non-static) and indirecting through an invalid reference is always undefined behaviour.

const int& func()
{
    return 5;
}

int main()
{
    const int& ref = func();
    std::cout<<ref; //But IS THIS UNDEFINED BEHAVIOR too?
}

Yes. You indirect through an invalid reference, and behaviour is undefined.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `func()` itself is probably fine but initializing a reference `const int& ref` may be undefined behaviour, because a reference must be initialized with a [valid object](https://eel.is/c++draft/dcl.ref#5.sentence-3), and the temporary in `func` has already been destroyed and its storage gone. Doesn't look like a problem if you had `const int* ptr = &func();`. This might be similar to how `int arr[5]; int& past_the_end = arr[5];` is illegal but `int* past_the_end = &arr[5];` isn't. – Artyer Dec 21 '22 at 06:00