-1

In C++ or for any other language, I wish to know that if a function returns a local variable in it's scope to a caller and assigns it to some other variable, how do the semantics work? An example in C++ which I have tried is as follows:

Code:

int my(){
    int t=10;
    cout<<&t<<"\n";
    return t;
}
int main() {
    const int& c=my();
    cout<<&c;
    return 0;
}

Output:

0x7fff71249164
0x7fff71249184

In the above example, I think I am passing it by reference so shouldn't the outputs be same? But I just happened to obtain different outputs. Also, I tried changing the return type of my() from int to int& but still got different outputs. I also tried passing using pointers, there too the outputs come out to be different. I just happened to study C++ recently and am getting confused, so any help would be greatly appreciated. Platform used: ideone online C++ (gcc 8.3)

I was expecting that for all my experiments, I would get equal values printed and the addresses would be the same. But is there something I am missing?

11
  • 3
    Look carefully at int my(). What is the return type? Commented Sep 25, 2024 at 20:26
  • 2
    Both results (same address or different one) are allowed in C++. Commented Sep 25, 2024 at 20:28
  • 1
    I was expecting that for all my experiments, I would get equal values printed and the addresses would be the same Why do you have that expectation? Commented Sep 25, 2024 at 20:34
  • 1
    I think I am passing it by reference There is no passing by reference at all in the code you show. int my() returns an int not a int& or const int& Commented Sep 25, 2024 at 20:38
  • 2
    Terminology: const int& c=my(); is initialization, not assignment. The = sign does double duty: when you create an object it's initialization; when you modify an already-existing object it's assignment. Commented Sep 25, 2024 at 20:57

1 Answer 1

5

my returns by-value, not by-reference, as specified by the return type int instead of int&. (And if you did return-by-reference, then you would have undefined behavior because the reference would be dangling after the call to my, because t lives only until then.)

A function call expression which calls a function that has a non-reference return type, such as my(), is a prvalue expression. (The same as kind of expression as e.g. an integer literal expression 42.)

When you initialize a const lvalue reference variable (e.g. c) with a prvalue expression, a temporary object is materialized from the prvalue and the reference is bound to that temporary object. The temporary object is initialized with the value of the prvalue expression and given an (extended) lifetime equal to that of the reference, i.e. the temporary object lives until the end of the scope of the reference.

This temporary object is generally a distinct object from the object belonging to the t variable. Because they are different objects, they do not need to have the same address. On the other hand, because the lifetime of t ends when the function my returns and the lifetime of the temporary object begins only after it has been initialized, their lifetimes do no overlap. Therefore the compiler would also be free reuse the memory of t for the temporary object so that the addresses would be the same. (The details are actually more complicated, but the end result the same for trivial types such as int. For non-trivial types the compiler may not be allowed to reuse memory in this situation, although the following paragraph still can have the same effect.)

Furthermore, a compiler is allowed to apply the so-called named return value optimization (NRVO), which allows the compiler to treat the temporary object and t as referring to the same object, thereby skipping any copies that would otherwise be necessary. In that case the addresses can also be the same. Compilers are not going to do this for type int, but may do so for more complex types.


All of the above applies only to C++. For example in C, the rules are different.

Sign up to request clarification or add additional context in comments.

7 Comments

C doesn't have reference variables to begin with, so this question wouldn't even make sense there.
Note that changing to a return type of int& wouldn't help because it would be a reference to an out-of-scope variable.
@Barmar The reference variable is a red herring. If v was of type int, then everything about the addresses would still apply in the same way.
@user17732522 Instead of using int, if I used static int then the lifetime of t would be for the entire program right? Then, I am getting the same addresses as output. So, is it because of the dangling reference of int& that the addresses are different(undefined behaviour). Is my understanding right? Thanks a lot for the answer.
@uvnarayan The temporary object can have the same address if memory is reused. But it doesn't need to. The compiler is free to choose where it puts each of the variables on the stack. If it is not reusing the same memory location, then you won't get the same address, yes.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.