2

In Cpp primer 5th Ed. p 393

If the function returns a lambda, then - for the same reasons that a function must not return a reference to a local variable - that lambda must no contain reference captures.

#include <iostream>
using namespace std;

auto foo(ostream &os) {
    auto f = [&os]() -> std::ostream& { os << "Hello World !" << endl; return os;};
    f();
    return f;
}
void main() {
    foo(cout);
    auto f = foo(cout);
    system("pause");
    f();
}

This code compiles without warning in msvc 2019. It also appears to run fine. The captured os referes to std::cout which exists outside of foo's scope. Is f() Undefined behaviour ? If yes, is auto f = foo(cout); also undefined behaviour (that is, the returning and assigning of the lambda) ?

user
  • 934
  • 6
  • 17
  • So long as the captured variable lives as long as the lambda, I think it's fine. – cigien May 01 '20 at 21:57
  • the captured variable being `os`, the local reference to `cout`, i reckon. It outlives the lambda, i think, i might be wrong – user May 01 '20 at 21:59
  • Defined behavior as far as I'm aware, as long as your lambda ain't called after destruction of the instance captured by lambda (and actually tried to use it), you are good to go – JVApen May 01 '20 at 22:00
  • I would rephrase it to: must not contain references to local variables – JVApen May 01 '20 at 22:01
  • I found a duplicate, which is essentially the same as your example. It captures an int by reference instead of a stream. – cigien May 01 '20 at 22:03

1 Answers1

1

I am no expert of C++ but when you return a lambda that captures a local variable by reference and the local variable gets discarded you run into a problem. This is because the captured variable no longer exists so you can't access it. The example you provided is a little bit different since you take the parameter by reference, hence it might still exist when the function returns. This might still be dangerous though because you have no way of knowing if someone passes in a parameter to get the lambda, then destroys the variable passed as parameter, and finally calls the lambda since now the lambda might want to use the captured variable but now it no longer exists.