What happens to the reference in function parameter, if it gets destroyed when the function returns, then how const int *i is still a valid pointer?
const int* func(const int &x = 5)
{
return &x;
}
int main()
{
const int *i = func();
}
§12.2/5:
"A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call."
That means as i is being initialized, it's getting the address of a temporary object that does exist at that point. As soon as i is initialized, however, the temporary object will be destroyed, and i will become just another dangling pointer.
As such, yes, the function is valid -- but with the surrounding code as you've written it, any code you added afterward that attempted to dereference i would give undefined behavior.
Just because a pointer has a value doesn't mean it's a valid pointer.
In this case it holds an address which used to be that of x, and chances are that address still has the value 5, but it's not valid pointer and you can't count on that value being there.
int i points to a patch of memory that is unsafe to access, it is not a valid pointer.
the variable "i" is still a pointer, but even reading the value it points to will give you undefined behavior. That's why you should never write a function like func.
I think that x is created as an un-named temporary on the stack in setting up the call to func(). This temporary will exist until at least the end of the statement in the caller. So the int* i is perfectly valid. It only ceases to be valid at the end of the statement - which means that you cannot use it.
There is something in the standard about un-named temporaries being retained until the last reference to them goes out of scope, but I don't think it covers this explicit and hidden indirection.
[ Happy to have someone tell me otherwise.]
5 is program data. It is in the data segment, not the stack or heap.
So a pointer or reference to it will remain valid for the duration of the program.
Default arguments are evaluated every time the function is called, so the call func() is actually func(5) which is binding a temporary to a reference-to-const. The lifetime of that temporary is then extended till the end of the function and the object is destroyed. Any pointer to this object after that is invalid and dereferencing it is undefined behaviour.
Related
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.
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.
Only for curiosity and educating and clarification reasons I would like to ask that the way I use references and values are good practices or not.
Theoretically:
class ComplexGraphicalShape {
...
public:
void setRasterImageURL(const QString &rasterImageURL);
const QString &rasterImageURL() const;
...
private:
const QString *_rasterImageURL;
};
...
void ShadowGram::setRasterImageURL(const QString &rasterImageURL) {
safeDelete(_rasterImageURL); // handle deletion
_rasterImageURL = new QString(rasterImageURL);
}
const QString &ShadowGram::rasterImageURL() const{
// Question 2: Why is it a problem if I return
// return "www.url.com/shape_url.jpg"
return *_rasterImageURL; // that is the right way
}
...
complexGraphicalShape().setRasterImageURL(kURLImagesToShare + imageName);
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg"); // Question 1.
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall? Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
My second question is that why I got a warning in Question 2 section if I would like to use this return "www.url.com/shape_url.jpg"? That thing is kind of similar. How long can I use that temporary object?
Thanks for your time for the answer and explanations
The temporary exists until setRasterImageURL returns, so you can safely pass a reference to it along, but you need to be careful not to save the reference for later. The temporary is stored wherever the compiler wants to. The reference is most likely passed either in a register or on the stack.
It is a problem because you're returning a reference to a temporary QString object, and that object is destroyed when the function returns. You're not allowed to use the reference at all.
Passing a reference "inwards" to a function is (usually) safe as long as you don't store it, while passing a reference "outwards" from a function requires you to make sure that the referenced object still exists when the function returns.
Q1: The temporary string exists as long as the temporary reference that is "bound" to it. That is - as long as you are "inside" setRasterImageURL() function. This - of course - includes all functions called "within" this function. Note that storing another reference to this temporary string does NOT prolong the lifetime of the temporary object.
complexGraphicalShape().setRasterImageURL("www.url.com/url.jpg");
// the temporary object is "destroyed" when it goes out of scope, and it's scope is just the called function
Q2: The problem with returning is that you use "C string" (array of characters) to create a temporary QString object (on stack, still inside the function) and return reference to that temporary. As this temporary object is destroyed right after this function returns, your reference is never valid and refers to a dead object. On the other hand - returning a reference to a member variable works, because this object is not destroyed, so the reference is valid as long as your main object lives.
const QString &ShadowGram::rasterImageURL() const{
return "www.url.com/shape_url.jpg"
// the temporary object is destroyed here, before the function returns, reference is invalid
}
My first question is that how long can I use the temporary object reference which is created inside setRasterImageURL functioncall?
It's not created inside the function call, it's created on the caller's stack before the function is called, and is destroyed after the function returns.
Where exist that variable?(in the stack If I am not mistaken, but what if I call another function with that temporary reference.
Yes, on the stack. It is destroyed at the ; after the function call returns (at the end of the "full expression").
That thing is kind of similar. How long can I use that temporary object?
Until the end of the full expression that creates the temporary, which is the return statement, so it goes out of scope immediately before the function has even finished returning. That's why you get a warning - the returned reference is bound to an object which no longer exists, and is never safe to use.
Both these cases are covered by 12.2 [class.temporary] paragraph 5 in the standard:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
— The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
Lets say I have following function, and it has an argument which is type T. What is life time of that argument.
int* f()
{
int x=0;
int* ptr=&x;
return ptr; //i know this is undefined behavior.
}
So in f() function when it s called, local expressios will run and end of scope pointed value will be deleted. But my question is for following function
void f2(int* y)
{
}
int main()
{
int p=0;
f2(&p);
cout<<p<<endl;
return 0;
}
Here, when we call f2() when that parameter int* y will be deleted? And so if its deleted logicaly pointed value will be deleted which is p, why I can see value of p same using cout? So when f2's argument will be deleted? when function's end scope? or what?
In void f2(int* y), you have a copy of a pointer. The lifetime of that pointer object y, extends to the end of the function f2.
In your main function, you have an integer p. The lifetime of p extends to the end of main.
When calling f2(&p), a temporary pointer is created to be passed to f2. It does not modify the lifetime of p. So, when f2 returns, the temporary pointer is no longer in scope, however p is still in scope (and therefore, valid).
All of the variables shown have automatic storage duration and do not require explicit "deletion".
The function does no memory management on arguments you pass it unless the argument is passed by value (technically everything is passed by value in c++, except a reference, but in the case of a pointer there isn't much to clean up). In the case of your code p is destructed when main's scope ends. Remember this is because p has automatic storage if it had dynamic storage it would be deleted only when you call delete on it.
Now in general there is no reason to pass around an automatic variable as a ptr because c++ has this great thing called pass by reference
void f2(int& y)
This is what you should be doing in most cases
A function parameter is just a local variable in the block scope of the function body. The difference between a function parameter and an ordinary block scope variable is that before the body begins executing, the function parameter is initialized from the corresponding function call expression.
The lifetime of the variable y extends only over the execution of the body of function f.
The object which the pointer object named y points to has a lifetime which is completely unrelated to y.
Pointers are not "deleted" automatically (in the sense that the delete operator is applied to them) at end-of-scope. The variable containing the address itself will be deleted, but the data it points to will not.
You might look at std::unique_ptr, which does what you're describing.
p is created on stack when main is entered. you call f and pass the address of p to it. The f's parameter y gets this address. y is also stored on stack. When f returns, y is deleted because it is a local variable, but p still exists and you print its value. Similar to y, the local variable p is deleted when main exits.
what happens when you dereference a pointer when passing by reference to a function?
Here is a simple example
int& returnSame( int &example ) { return example; }
int main()
{
int inum = 3;
int *pinum = & inum;
std::cout << "inum: " << returnSame(*pinum) << std::endl;
return 0;
}
Is there a temporary object produced?
Dereferencing the pointer doesn't create a copy; it creates an lvalue that refers to the pointer's target. This can be bound to the lvalue reference argument, and so the function receives a reference to the object that the pointer points to, and returns a reference to the same. This behaviour is well-defined, and no temporary object is involved.
If it took the argument by value, then that would create a local copy, and returning a reference to that would be bad, giving undefined behaviour if it were accessed.
The Answer To Your Question As Written
No, this behavior is defined. No constructors are called when pointer types are dereferenced or reference types used, unless explicitly specified by the programmer, as with the following snippet, in which the new operator calls the default constructor for the int type.
int* variable = new int;
As for what is really happening, as written, returnSame(*pinum) is the same variable as inum. If you feel like verifying this yourself, you could use the following snippet:
returnSame(*pinum) = 10;
std::cout << "inum: " << inum << std::endl;
Further Analysis
I'll start by correcting your provided code, which it doesn't look like you tried to compile before posting it. After edits, the one remaining error is on the first line:
int& returnSame( int &example ) { return example; } // semi instead of colon
Pointers and References
Pointers and references are treated in the same way by the compiler, they differ in their use, not so much their implementation. Pointer types and reference types store, as their value, the location of something else. Pointer dereferencing (using the * or -> operators) instructs the compiler to produce code to follow the pointer and perform the operation on the location it refers to rather than the value itself. No new data is allocated when you dereference a pointer (no constructors are called).
Using references works in much the same way, except the compiler automatically assumes that you want the value at the location rather than the location itself. As a matter of fact, it is impossible to refer to the location specified by a reference in the same way pointers allow you to: once assigned, a reference cannot be reseated (changed) (that is, without relying on undefined behavior), however you can still get its value by using the & operator on it. It's even possible to have a NULL reference, though handling of these is especially tricky and I don't recommend using them.
Snippet analysis
int *pinum = & inum;
Creates a pointer pointing to an existing variable, inum. The value of the pointer is the memory address that inum is stored in. Creating and using pointers will NOT call a constructor for a pointed-to object implicitly, EVER. This task is left to the programmer.
*pinum
Dereferencing a pointer effectively produces a regular variable. This variable may conceptually occupy the same space that another named variable uses, or it may not. in this case, *pinum and inum are the same variable. When I say "produces", it's important to note than no constructors are called. This is why you MUST initialize pointers before using them: Pointer dereferencing will NEVER allocate storage.
returnSame(*pinum)
This function takes a reference and returns the same reference. It's helpful to realize that this function could be written with pointers as well, and behave exactly the same way. References do not perform any initialization either, in that they do not call constructors. However, it is illegal to have an uninitialized reference, so running into uninitialized memory through them is not as common a mistake as with pointers. Your function could be rewritten to use pointers in the following way:
int* returnSamePointer( int *example ) { return example; }
In this case, you would not need to dereference the pointer before passing it, but you would need to dereference the function's return value before printing it:
std::cout << "inum: " << *(returnSamePointer(pinum)) << std::endl;
NULL References
Declaring a NULL reference is dangerous, since attempting to use it will automatically attempt to dereference it, which will cause a segmentation fault. You can, however, safely check if a reference is a null reference. Again, I highly recommend not using these ever.
int& nullRef = *((int *) NULL); // creates a reference to nothing
bool isRefNull = (&nullRef == NULL); // true
Summary
Pointer and Reference types are two different ways to accomplish the same thing
Most of the gotchas that apply to one apply to the other
Neither pointers nor references will call constructors or destructors for referenced values implicitly under any circumstances
Declaring a reference to a dereferenced pointer is perfectly legal, as long as the pointer is initialized properly
A compiler doesn't "call" anything. It just generates code. Dereferencing a pointer would at the most basic level correspond to some sort of load instruction, but in the present code the compiler can easily optimize this away and just print the value directly, or perhaps shortcut directly to loading inum.
Concerning your "temporary object": Dereferencing a pointer always gives an lvalue.
Perhaps there's a more interesting question hidden in your question, though: How does the compiler implement passing function arguments as references?