Ok, so, I already know that returning a local variable as reference will cause undefined behavior when we try to use it and that we can create a non-const reference to only form a lvalue variable. Creating a const reference does not need to be created from a lvalue variable, because if it is created from a non-lvalue variable, it creates a temporary one in that scope (code below).
const int& refa {2};
// basically equals
const int temp_a{2};
const int& refa{temp_a};
And there goes my question, if we pass a non-lvalue as a parameter to a function that takes a const reference, will the temporary variable be created in local scope of the caller or in local scope of the function? I am curious if returning the argument as reference and using it will cause undefined behavior. Sample (assume that the method is not inline):
_declspec(noinline) const int& inMax(const int& a, const int& b)
{
return a > b ? a : b;
}
int main()
{
int a{ 5 }, b{ 6 };
// Will the temporary variables for POST decrementation/incrementation result
// will be created here or inside inMax(...)
const int& ret = inMax(a++, b--);
// is the ret safe to use?
}
No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .
Prefer pass by value for objects that are cheap to copy, and pass by const reference for objects that are expensive to copy. If you're not sure whether an object is cheap or expensive to copy, favor pass by const reference.
From what I understand: when you pass by value, the function makes a local copy of the passed argument and uses that; when the function ends, it goes out of scope. When you pass by const reference, the function uses a reference to the passed argument that can't be modified.
Passing By Reference To Const in C++ C++ is an example of a message-passing paradigm language, which means that objects and values are passed to functions, which then return further objects and values based on the input data.
It will be created in the scope of the calling function (the called function can't tell if it has been passed an rvalue it needs to destruct, or a real lvalue). That's the good news. The bad news is that the temporary will be destroyed at the end of the full expression which includes the function call.
The compiler will transform your code into something like:
const int& ret; // Not yet initialized
{
const int tempA = a++;
const int tempB = b--;
ret := inMax(tempA, tempB); // Initialize ret with reference to tempA or tempB
// destroy tempB, and tempA
}
// ret is now a dangling reference.
However. Unlike the "return referencee to local variable" case, it is valid to use the function result in the statement which contains the function call. Thus:
int ret = inMax(a++,b--);
is valid. In this case, ret
is copy constructed from the reference - which is not yet dangling. Also, if the function returns a reference to a class object, it is safe to call a member of that class in the same statement.
Having said all that, this is highly risky territory. If someone comes along later and splits a long complex statement into several parts, they can introduce undefined behaviour.
The temporaries will be destroyed after the full expression where they're created.
All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created
So
const int& ret = inMax(a++, b--); // two temporaries are created and passed to inMax as arguments
// is the ret safe to use?
// No, temporaries has been destroyed and ret is a dangled reference
will the temporary variable be created in local scope of the caller or in local scope of the function?
They're created at the caller site. Anyway it doesn't matter, the answer to your question won't change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With