Is it safe to commit a member reference if the class that stores the original link is out of scope?

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, since the actual referent still exists when the task is completed, we get a linked link during lambda, and everything is fine.

However, on my GCC 4.8.5 (CentOS 7), I see some behavior (in a more complex program) that assumes that this is instead of UB, because f and the fx link itself died, Is this correct?

+8
c ++ lambda c ++ 11
source share
2 answers

To fix a link to a member, you need to use 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'; }; } }; 

thus l_x is int & stored in closure, and referring to the same value int m_x refers to and is not affected by Foo , which goes out of scope.

In C ++ 11, we can bypass this function, which is missing when writing a value instead of a pointer:

 struct Foo { int & m_x; void bar() { int * p_x = &m_x; task = [=]() { std::cout << *p_x << '\n'; }; } }; 
+9
source share

You can capture a reference element in C ++ 11 by creating a local copy of the reference and explicit capture to avoid this capture:

 void bar() { decltype(x) rx = x; // Preserve reference-ness of x. static_assert(std::is_reference<decltype(rx)>::value, "rx must be a reference."); task = [&rx]() { std::cout << rx << ' ' << &rx << '\n'; }; // Only capture rx by reference. } 
+3
source share

All Articles