Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lambda: should capturing const reference by reference yield undefined behaviour?

I just found a nasty bug in my code because I captured a const reference to a string by reference. By the time the lambda was run the original string object was already long gone and the referenced value was empty whereas the purpose was that it would contains the value of the original string, hence the bug.

What baffles me is that this did not invoke a crash at runtime: after all, shouldn't this be undefined behaviour since afaik there is a dangling reference? Moreover when looking at id under the debugger, it doesn't even look like garbage but just like a properly constructed empty string.

Here's the test case; this just prints an empty line:

typedef std::vector< std::function< void() > > functions;

void AddFunction( const std::string& id, functions& funs )
{
  funs.push_back( [&id] ()
    {
        //the type of id is const std::string&, but there
        //is no object to reference. UB?
      std::cout << id << std::endl;
    } );
}

int main()
{
  functions funs;
  AddFunction( "id", funs );
  funs[ 0 ]();
}
like image 583
stijn Avatar asked Jan 19 '23 04:01

stijn


2 Answers

Undefined behavior means there is no requirement what should happen. There is no requirement that it should crash. Whatever memory your dangling reference points at, there's no reason it shouldn't contain something that looks like an empty string, and it's plausible that the destructor of string leaves the memory in that state.

like image 100
Steve Jessop Avatar answered Jan 25 '23 19:01

Steve Jessop


Capturing anything by reference means that you have to take care that it's alive long enough. If you don't the program may just work, but it might just call Domino's and order a double pepperoni. At least, according to the standard.

like image 28
dascandy Avatar answered Jan 25 '23 21:01

dascandy