1

If an automatic is bound to a lambda function, does the life of the automatic get extended to the life of the lambda function?

Simplest case:

auto genfunc (int start)
{
     int count=start;
     return [&count] {
         return count++;
     };
}

Is this fine, or undefined behavior?

Praetorian
  • 106,671
  • 19
  • 240
  • 328
Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80

2 Answers2

6

No, the lifetime of count is not extended because you capture it by reference. Lifetime extension rules are listed in §12.2 [class.temporary], items 4 & 5, and neither include capture by reference in a lambda.

Invoking the lambda returned by genfunc will result in undefined behavior. This is mentioned in a note in §5.1.2/24 [expr.prim.lambda]

[ Note: If an entity is implicitly or explicitly captured by reference, invoking the function call operator of the corresponding lambda-expression after the lifetime of the entity has ended is likely to result in undefined behavior. —end note ]

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • @vsoftco gcc-5.1 does [produce a warning](http://coliru.stacked-crooked.com/a/d3858dd947c230f0), but it's not the most intuitive warning I've seen. clang just prints out garbage. – Praetorian Aug 03 '15 at 20:23
  • I don't think it's fair to expect C++ to catch this kind of thing. Unless C++ goes full [Rust](https://en.wikipedia.org/wiki/Rust_%28programming_language%29), it will never be possible to catch everything. It's nice that some blatant code is warned about, e.g. `return count;`, but this is complex. – Aaron McDaid Aug 03 '15 at 20:24
5

does the life of the automatic get extended to the life of the lambda function?

No. The lambda might be confusing here, so let's rewrite it to be a struct:

struct X
{
    int operator()() const { return ref++; }

    int& ref;
};

auto genfunc (int start)
{
    int count=start;
    return X{count};
}

The X object that we created holds a reference (ref) to a temporary (count) that goes out of scope as soon as the object is returned. There's nothing special about the lambda - a dangling reference is a dangling reference.

There's no reason to keep the reference though, just capture by-value:

auto genfunc (int start)
{
     return [start]() mutable {
         return start++;
     };
}

Note the required mutable keyword.

Barry
  • 286,269
  • 29
  • 621
  • 977