Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing non-lvalue as const reference argument. Is the temp created in local scope or caller scope?

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?
}
like image 460
Dawid Wdowiak Avatar asked Jun 15 '18 05:06

Dawid Wdowiak


People also ask

Can a const reference be bound to a non const object?

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 .

What is the difference between pass by value pass by reference and passing a const reference to a function when would you use each?

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.

What is the difference between pass by reference and 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.

What is passing by const reference?

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.


2 Answers

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.

like image 200
Martin Bonner supports Monica Avatar answered Nov 15 '22 06:11

Martin Bonner supports Monica


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.

like image 31
songyuanyao Avatar answered Nov 15 '22 07:11

songyuanyao