is there any difference between these two pieces of code? (temp variable) - c++

Is there any difference between these two pieces of code?
CPoint temp(x,y);
some_func(temp);
and
some_func(CPoint(x,y));

The lifetime of the CPoint objects is different.
In the first case, a variable named 'temp' is created. It will not be destroyed until after the scope within which it is declared is exited.
In the second case, a true temporary value is created and passed to the function, which will be destroyed as soon as some_func has returned.

Yes, in the first case, the temp var will not be destroyed until the end of the scope. In the second case it will be.
If your function some_func() takes a non const reference as a parameter, the second will not compile since you can not have a reference to something which will be destroyed right away (when some_func returns).
In the first case, if your some_func() function takes a reference, you should be aware that the temp variable will only exist until the current scope ends.

Related

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.

Best practices with references

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.

Life time of function argument in c++

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.

about string.c_str() life cycle

I wonder if the void func(const char *str); refer to a valid str if I wrote as follow:
auto str = string("hello").c_str();
func(str);
How is it different from code below?
func(string("hello").c_str())
In both cases, the string object is a temporary, destroyed at the end of the statement.
In the first case, str ends up dangling - pointing to memory that was managed by the temporary string, but which has now been destroyed. Doing anything with it is an error, giving undefined behaviour.
In the second case, the temporary string is not destroyed until after the function returns. So this is fine, as long as the function doesn't keep hold of the pointer for something else to use later.
The difference is that the first creates a temporary string object that gets destroyed at the end of the first statement, so str becomes a dangling pointer. The second also creates a temporary, but it exists throughout the call to func because the temporary object doesn't get destroyed until after the call to func returns.
From Paragraph 12.2/3 of the C++11 Standard:
[...] Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. [...]
This means that the temporary created within the expression that contains the call to func() will live until function call returns.
On the other hand, the lifetime of the temporary in the first code snippet will end up before func() is invoked, and str will be dangling. This will result in Undefined Behavior.

Is this a valid function?

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.