returning references to local variable [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Returning the address of local or temporary variable
Can a local variable’s memory be accessed outside its scope?
Even knowing what happens as a result of the following snips it would be helpful to understand how it is happening. Four questions follow.
Given:
int& foo()
{
int i = 1;
return i;
}
And knowing that in the following a reference to the local named i is de-referenced into a temp that is assigned to intVal and local i disappears at the end of foo()
int intVal = foo();
First question - in the following, the right hand side of the expression is the same as above so is this a case where the compiler sees the left hand side and, based on context, knows not to de-reference the returned reference, and instead to create a new reference is initialized with it?
Second question - and this alone makes the local i stick around while intRef is in scope?
int& intRef = foo();
Third question - bellow intPtr gets address of local i. So, is the compiler using the context of the assignment and deciding to not de-reference to get a value before taking the address of the reference (rather than say taking the address of a temp containing the de-referenced value)?
Fourth question - does local i stick around while intPtr is in scope?
int* intPtr = &foo();

Nope, none of those will extend the lifetime of the local variable. Nothing in C++ will have that effect. Local objects in C++ live until the end of the scope in which they are declared, end of story.
The only rule which, at first glance, seems to follow different rules is this:
int foo() {
return 42;
}
int main() {
const int& i = foo();
// here, `i` is a reference to the temporary that was returned from `foo`, and whose lifetime has been extended
}
That is, a const reference can extend the lifetime of a temporary being assigned to it.
But that requires the function to return a value, not a reference, and the callee to bind the return value to a const reference, neither of which are done in your code.

In no case (not intVal, not intRef, and not intPtr) does i necessarily stick around after foo returns.
The value on the stack which was previously occupied by i may or may not be changed at any time, after foo returns.
For example (on some CPUs and O/Ses), it is likely to be changed by any subsequent call to a subroutine, and may be changed if a hardware interrupt occurs.

Related

Why is the newly added node not displaying after it is successfully added in the Linked List [duplicate]

Is passing pointer argument, pass by value in C++? Since i see that any change to the pointer as such is not reflected outside the method. The changes i do by dereferencing the pointer is reflected though.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
Yes to both.
Pointers are passed by value as anything else. That means the contents of the pointer variable (the address of the object pointed to) is copied. That means that if you change the value of the pointer in the function body, that change will not be reflected in the external pointer that will still point to the old object. But you can change the value of the object pointed to.
If you want to reflect changes made to the pointer to the external pointer (make it point to something else), you need two levels of indirection (pointer to pointer). When calling functions it's done by putting a & before the name of the pointer. It is the standard C way of doing things.
When using C++, using references is preferred to pointer (henceforth also to pointer to pointer).
For the why references should be preferred to pointers, there is several reasons:
references introduce less syntaxic noise than pointers in function body
references keep more informations than pointers, than can be useful for compiler
Drawbacks of references are mostly:
they break the simple pass-by-value rule of C, what makes understanding the behavior of a function regarding of parameters (will they be changed ?) less obvious. You also need function prototype to be sure. But that is not really worse than the multiple pointer levels necessary when using C.
they are not supported by C, that can be a problem when you write code that should work with both C and C++ programs (but that's not the most usual case).
In the specific case of pointer to pointer, the difference is mostly simplicity, but using reference it may also be easy to remove both levels of pointers and pass only one reference instead of a pointer to pointer.
I understand the confusion here. The concepts of "pass by value" and "pass by reference" are not so clear even if they seem to be so.
Bear in mind that the computer does not know these concepts and does not behave according to it.
The computer does not know about the types. Hence it does not make a distinction of pointers and values.
Let me try to explain by and example:
void func1(int x) //copy some value to local variable x (of type int)
{
x = 5; //modify local variable. lost after function call
}
void func2(int *x) //copy some value to local variable x (of type int*)
{
int a;
x = &a; //modify local variable. lost after function call.
}
void func3(int *x) //copy some value to local variable x(of type int*)
{
*x = 10; //x is local but *x is not! change is saved after function call!
}
func1 and func2 are identical. Both modify a local variable. Modification is lost after function is popped off the stack.
func3 has ability to change another memory location (a variable which is not local to the function).
basically, every function call is "call by value". But in the case of a pointer type, we have a way to change the content of a remote address in memory.
Pass by value using Pointers
I'll explain it by example:
void f(int *ptr)
{
cout<<*ptr;
}
int main ()
{
int a=10;
int *aptr=&a;
f(aptr);
return 0;
}
Here, in main function a is an integer variable whose content is 10 and address is 00F8FB04 (assume).
aptr is pointer to integer, that store the address of integer variable a, so aptr content is address of integer variable a that is 00F8FB04. When we pass aptr as the function argument only content of aptr (that is address) are copies to function parameter.
So, ptr will receive the copy of content of aptr (that is address 00F8FB04)
Either a pointer to a pointer, or a reference to a pointer, is what you would use if you wanted to potentially change the pointer itself. To your original question, technically, yes, all parameters are passed by value.
Yes it is, as it is in C.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
In which case? What do you want? You can use real references with the & modifier.
void func(type &ref);

My misconception about pass by and return by reference in C++

Pass by reference:
I have learned that when a variables is passed as a reference to a function then instead of copy, the actual data is passed to the function but i think that if it is really the case then we shouldn't be able to access that data again once the program execution returns to main() after the stack frame of that function gets destroyed and leave that reference variable with zero or null value in main() but it is not the case and we can still access it in the main() so i think that in pass by reference, the memory address of that variable is passed to that function reference variable parameter and then we use that memory in that function with another name(reference variable) and when that function gets destroyed then the reference variables get destroyed rather than the actual data.
is my thinking towards this concept is right or am i doing some mistake in understanding this concept ?
Return By Reference
When a variable which is passed as a reference to another function returns back as a reference to main() then is the memory address passed back to main() or what actually is returned ?
I have learned that when a variables is passed as a reference to a function then instead of copy, the actual data is passed to the function
This is wrong. Passing the actual data would mean the value is passed (either by copy or by move). When passing by reference, a reference to the actual data is passed to the function.
so i think that in pass by reference, the memory address of that variable is passed to that function reference variable parameter and then we use that memory in that function with another name(reference variable)
This is right.
When a variable which is passed as a reference to another function returns back as a reference to main() then is the memory address passed back to main() or what actually is returned ?
A reference can be thought of as a memory address, so returning a reference is similar to returning a pointer (memory address).
When returning a reference from a function, you need to be careful that you don't return a reference to a variable that's local to the function, because that variable no longer exists after the function returns, and you are left with a dangling reference that may crash your program when you try to use it.
passed as a reference to a function then instead of copy, the actual data is passed to the function
It is unclear what you mean by "actual" data. A copy is actual data as much as the origianl object is.
References are a form of indirection. The reference variable indirectly refers to the object to which it was bound. An object variable is distinct from other objects, and its value may be copied from another.
if it is really the case then we shouldn't be able to access that data again once the program execution returns to main()
Binding a reference to an object does not make the object or its data disappear. Example:
void foo(int& ref);
int main()
{
int obj;
foo(obj);
// obj still exists here
}
If you bind a reference to an object defined in main, then the object still exists in main regardless of where that reference was bound.
i doing some mistake in understanding this concept ?
Yes. You did not understand yet what a reference is, or at least were not able to describe them correctly.
Your concept of pass by reference is wrong.
Passing a variable to a function by reference means that something else (let's call it a handle) is passed that acts an alias of the original variable. Every operation that can be performed on the handle within the function (e.g. assigning it a value, retrieving its value, calculating its address, calling a member function if it is an object) are referred to the original variable that was passed by the caller. How those affects are achieved depends on the implementation (e.g. the compiler).
The called function, by performing operations on the handle, does not cause the original variable to cease to exist. (Except in some very specific circumstances, which I won't go into).
For example;
#include <iostream>
void foo(int &x)
{
x = 42; // x is the handle I refer to above
}
int main()
{
int y = 16;
std::cout << y << '\n';
foo(y);
std::cout << y << '\n';
}
will print the values 16 and 42, in that order. The assignment x = 42 in foo() has the effect of changing the value of y in main(). The lifetime of y is unaffected, so y continues to exist until the end of main().
That thing I have referred to as a "handle" is more commonly known as a reference.
Similarly, your concept of returning a reference is wrong. Returning a reference gives a handle to the caller, and the caller can then use the returned handle to access (and perform operations on) whatever variable is returned by the function.
Note that, in the above, I have said nothing about passing the address of a variable around. Because the description above focuses on the observable effect of using references, not on how that observable effect is achieved (e.g. by the compiler).
Behind the scenes, your compiler MIGHT implement all of the magic of references by passing the address of the affected variables around (in fact, most modern compilers do). That is one possible implementation approach. But there are, technically, other ways of achieving that effect - the C++ standard does not require the address of variables to be passed around to achieve the behaviours associated with passing them around by reference.

Is it safe to return local struct variable's member variable?

struct SGetWindow
{
HWND__* pWindow;
};
SGetWindow getWindow;
EnumWindows(GetWindowProc, reinterpret_cast<LParam>(&getWindow));
return getWindow.pWindow;
Using SGetWindow struct as LParam, HWND__* pWindow is successfully updated.
I wonder if this usage of returning member variable of local struct variable is safe.
return getwindow.pWindow;
Is it safe? or cause undefined behavior?
EDIT: I added an image for understanding.
I understood that the value of pointer (0x00000000000506D8 or 0x00000000000606D8) 1) is valid after function termination, 2) will be copied. But I don't think that guarantees safeness because the matter it seems is 'access (local struct member variable that no longer exist), and return its value'.
EDIT2:
I was thinking wrong and I was so dumb.
According to what I was thinking, even returning local int variable would lead to undefined behavior. For example,
int func()
{
int a = 10;
return a;
}
Local variable 'a' no longer valid when function exits. Thus, return value is undefined behavior.
However, this isn't. Because it is 'return by value' type. The value is copied (somewhere), and the copy process is before local variable goes out of scope.
Operation sequence would be something like
Allocate n bytes for local variable and set its value as 10.
2. Copy the local variable's value to 'somewhere'.
Function exits and local variables become invalid (reverting EBP).
"Another advantage of return by value is that you can return variables (or expressions) that involve local variables declared within the function without having to worry about scoping issues. Because the variables are evaluated before the function returns, and a copy of the value is returned to the caller, there are no problems when the function’s variable goes out of scope at the end of the function."
https://www.learncpp.com/cpp-tutorial/74a-returning-values-by-value-reference-and-address/
"The copy-initialization of the result of the function call is sequenced-before the destruction of all temporaries at the end of expression, which, in turn, is sequenced-before the destruction of local variables of the block enclosing the return statement."
https://en.cppreference.com/w/cpp/language/return
EBP revert
https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames
Shame on me!
Thank you for kind answers by the way.
This is safe.
You're returning the value of getWindow.pWindow, which happens to be a pointer. This pointer was populated by a call to EnumWindows, not by assigning the address of a local variable.
It's fine, assuming the address in pWindow will continue to exist after the function returns. You can't return a pointer to pWindow (&getWindow.pWindow), but you can return its value (getWindow.pWindow), as long as the value remains valid. pWindow is destroyed when the function returns but that's okay since its value is being copied. If pWindow points to a local variable then you can't do it, but if it points elsewhere then it's safe.

Implications of not assigning the return value of a function to a variable

I'm going through some introductory C++ exercises, one of which is: What's going to be on the screen after running this code:
int& testMethod (int& a){
int c = a+a;
return c;
};
int main() {
int z = 5;
int* y = new int (testMethod(z));
int r = 25;
testMethod(r);
std::cout<<*y;
return 0;
}
My questions are:
Am I right that this is an example of UB as the value returned by testMethod on the second call is not getting assigned to a variable?
Is it true that the return value, although not assigned to a variable, might still be recovered but it depends?
For No 2, I'm just trying to confirm my understanding of how the stack works, which is as follows. When a function returns a value and the value gets assigned to a variable, the result of the calculations is firstly stored on the stack as retval at some memory location and then gets assigned to the variable, i.e. written to another memory location. The stack pointer then moves up (again, from what I understand, the 'top' of the stack is actually its 'bottom' as the pointer moves from the largest address to the smallest). But retval is still there for some time until it gets overwritten by another piece of data (which might happen almost instantly).
This second question arose when I was looking for an answer to the first question on SO and found this thread, as the two top (by votes) posts answer differently.
How automatic allocation is implemented on your particular platform is irrelevant. Your codes does trigger UB, not because you ignore the return value of testMethod (which, by the way, is not a method) but on the contrary because the following line uses it:
int* y = new int (testMethod(z));
The issue is that testMethod always returns a dangling reference to what was its local variable c. Using this reference to initialize the dynamically-allocated int triggers UB.
Predictably, enabling warnings (which you should always do) produces the following:
warning: reference to stack memory associated with local variable 'c' returned [-Wreturn-stack-address]
Am I right that this is an example of UB as the value returned by
testMethod on the second call is not getting assigned to a variable?
Maybe you didnt notice yet, but you are ignoring the returned value all the time (sloppy speaking). For example std::cout << *y; returns a reference to std::cout, otherwise you could not chain it as in
std::cout << "hello" << "world";
No. Ignoring the returned value is not undefined. Sometimes you cannot avoid to ignore the returned value (just another example: assignment usually returns a reference, ie you can write a = b = c; but usually you just write b = c; a = b;).
For 2) you are too much considering implementation details. Dont overcomplicate it. You ignore the value, thats all.
PS: your code has UB, but for completely different reason (see other answer).

Assigning not by-reference variable to a function returning by-reference, and vice-versa

While this may be a simple question, I was not able to find an answer probably because these situations are not covered in your standard pass-by-value and pass-by-reference tutorials. I am familiar with both principles, but I cannot pinpoint exactly what the compiler does in the following two scenarios. I am looking for an explanation as to what happens on the stack and when the compiler makes any copies of objects versus simply assigning addresses.
Consider the following function:
int & foo();
What happens when a is not by-reference?
int a = foo(); // a is not int &
Consider the next function:
int bar();
What happens when b is by-reference?
int & b = bar(); // bar is not by-reference
The values of both expressions foo() and bar() are values of type int. The former is an lvalue, and the latter is an rvalue. When you say int a = foo(); or int a = bar(), the local object variable a is initialized with that value. When you say int & b = foo(), the local reference variable b is bound to the value on the right (which is an lvalue). The statement int & b = bar() is invalid because references cannot bind to rvalues.
In the first case simply the value is copied from what is currently contained in the object referenced by the reference returned by the function.
The second case is illegal with a non-const reference, in case of a const reference instead the referenced object returned by the function will be kept alive until the reference goes out of scope (there is a very specific rule for this in the C++ language).
In the first case, the object that the reference is bound to (i.e., the object denoted by the value returned) is copied into a. No temporary is introduced to hold the return value.
In the second case, it won't compile, since bar() is an rvalue.