Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to capture a member reference if the class storing the original reference goes out of scope?

Tags:

c++

c++11

lambda

Consider this:

#include <iostream>
#include <functional>

std::function<void()> task;
int x = 42;

struct Foo
{
   int& x;

   void bar()
   {
      task = [=]() { std::cout << x << '\n'; };
   }
};

int main()
{
   {
      Foo f{x};
      f.bar();
   }

   task();
}

My instinct was that, as the actual referent still exists when the task is executed, we get a newly-bound reference at the time the lambda is encountered and everything is fine.

However, on my GCC 4.8.5 (CentOS 7), I'm seeing some behaviour (in a more complex program) that suggests this is instead UB because f, and the reference f.x itself, have died. Is that right?

like image 833
Lightness Races in Orbit Avatar asked Dec 01 '17 11:12

Lightness Races in Orbit


1 Answers

To capture a member reference you need to utilize the following syntax (introduced in C++14):

struct Foo
{
   int & m_x;

   void bar()
   {
      task = [&l_x = this->m_x]() { std::cout << l_x << '\n'; };
   }
};

this way l_x is an int & stored in closure and referring to the same int value m_x was referring and is not affected by the Foo going out of scope.

In C++11 we can workaround this feature being missing by value-capturing a pointer instead:

struct Foo
{
   int & m_x;

   void bar()
   {
      int * p_x = &m_x;
      task = [=]() { std::cout << *p_x << '\n'; };
   }
};
like image 113
user7860670 Avatar answered Oct 12 '22 20:10

user7860670