3

For a function T& f() {...} what will be the lifetime of the reference entity created in T x = f(); ?

According to the standard "The lifetime of a reference begins when its initialization is complete and ends as if it were a scalar object.", and while there is a section concerning temporary objects, a reference is not an object so it doesn't seem to apply.

Does this mean that according to the standard, in the example above the reference must actually exist throughout the whole scope block in which T x = f(); lies? That would seem redundant. I can't see any issue if the reference here were treated similarly to how "temporary" objects are - it seems safe for it to stop existing at the end of the full expression in which it is contained.

Jake1234
  • 187
  • 1
  • 7
  • The type of the expression `f()` is actually `T` and not `T&`, so you're not actually creating a reference variable `x` but a normal non-reference variable `x`. – Jason Oct 14 '22 at 16:41
  • The lifetime rule for references is as far as I can tell only significant at all in order to describe the lifetime of temporary objects to which the reference is bound and extends lifetime. But references as return values explicitly do not extend lifetime of temporaries, so there is basically no significance to what the lifetime of such a reference would be. – user17732522 Oct 14 '22 at 17:02
  • If you had created a reference, `T& x=f();` then there are two lifetimes to consider. That of the reference which you quote from the standard, and that of the object the reference aliases. Should the former last longer than the latter, you will have a dangling reference. This is similar to how pointers behave. – doug Oct 14 '22 at 17:04
  • 1
    I am also not sure whether the `return` statement is really supposed to initialize a reference. I think the current wording just says that so that the initialization rules for reference variables can be reused in the sense that there is an imagined declaration of a reference initialized by the operand of the return statement. The glvalue result of the function call is then denoting the same object/function as this initialized variable would. But I don't see that being clear in the standard. – user17732522 Oct 14 '22 at 17:05
  • 2
    _For a function `T& f() {...}` what will be the lifetime of the reference entity created in `T x = f();` ?_ There is no reference here. `x` is initialized by the `return`'s operand. – Language Lawyer Oct 14 '22 at 18:40
  • 1
    @LanguageLawyer Does that mean there is no reference initialization involved in `T x = f();` given that `T` is a nonreference type like `double` etc? – Alex Oct 14 '22 at 19:07

1 Answers1

1

Does this mean that according to the standard, in the example above the reference must actually exist throughout the whole scope block in which T x = f(); lies?

Yes, the type of the expression f() is actually T and not T&(because in C++ the type an expression is never a reference type), so you're not actually creating a reference variable x but a normal non-reference variable x. And so the normal scoping rules apply.

Basically, x is being initialized with the value referred to by the reference. From expression's documentation

Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories: prvalue, xvalue, and lvalue.

For example,

int& f()
{
    static int i = 0; 
    return i;
}
int main()
{
    {
        int x = f(); //x is a copy of i
        //you can use x here in this block 
    }//scope of x ends 
    
    //can't use x here
}
Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    [tag:language-lawyer] tag asks for standard quote to back up the answers. – Yksisarvinen Oct 14 '22 at 16:47
  • @Yksisarvinen I don't know what to quote here. I mean OP already know what scope is. So, i haven't added anything new here. Just cleared. Anyway i will add a reference to why an expression is never a reference in c++. – Jason Oct 14 '22 at 16:48
  • According to https://en.cppreference.com/w/cpp/language/reference_initialization#Explanation however, "References are initialized in the following situations: ... 4) In the `return` statement, when the function returns a reference type" Does this not conflict with what you are saying? How is the lifetime of this reference determined? – Jake1234 Oct 14 '22 at 16:49
  • @Jake1234 `T x = f();` is **copy initialization** while `T &x = f();` is **reference initialization**. You have the former in your question. Note carefully the title of the page whose link you gave it says: [Reference initialization](https://en.cppreference.com/w/cpp/language/reference_initialization#Explanation) – Jason Oct 14 '22 at 16:53
  • 2
    OP is not confused about initialization, they know it's a copy initialization and `x` is not a reference. They ask about lifetime of reference created by `return something;` in `f()`. The answer to that would be "it ends by the `;`", but that would require proper explanation as well. I'd probably ask if the reference is even bound at any point, or if it's skipped. And I'm not sure how to interpret "Each expression has some non-reference type" if `decltype(f())` is clearly a `T&`: https://godbolt.org/z/sq1dYf1We – Yksisarvinen Oct 14 '22 at 17:01
  • @Yksisarvinen Yes, this is what I am confused about - according to the "4) In the return statement, when the function returns a reference type" is would seem that even a simple call `f();` should be initializing a reference. – Jake1234 Oct 14 '22 at 17:07
  • @Jake1234 See also [Is a reference's lifetime distinct from the object it refers to?](https://stackoverflow.com/questions/9291371/the-lifetime-of-a-reference-with-regard-to-its-target) – Jason Oct 14 '22 at 17:09
  • @Yksisarvinen `decltype(f())` is not even an expression. So atleast the last part of your last comment is wrong. – Alex Oct 14 '22 at 19:59
  • _And I'm not sure how to interpret "Each expression has some non-reference type" if `decltype(f())` is clearly a `T&`_ Do you see inconsistence or controversy here? [The type of an indirection expression `*ptr` is (a non-reference type) `T`](https://timsong-cpp.github.io/cppwp/n4868/expr.unary.op#1.sentence-2), but `decltype(*ptr)` is `T&`. – Language Lawyer Oct 15 '22 at 10:09
  • 1
    @Yksisarvinen The point is that `decltype` has special rules and that is why we get `T&` in your example. But that doesn't prove that `f()` is `T&` or `const T&`. An expression is always a non-reference type in C++. – Jason Oct 15 '22 at 10:19