C++11 lambdas: member variable capture gotcha
Is this behaviour specified by the standard
Yes. Capturing member variables is always done via capturing this
; it is the only way to access a member variable. In the scope of a member function a_
is equivalent to (*this).a_
. This is true in Lambdas as well.
Therefore, if you use this
(implicitly or explicitly), then you must ensure that the object remains alive while the lambda instance is around.
If you want to capture it by value, you must explicitly do so:
std::function<void()> getf()
{
auto varA = a_;
return [=]() { varA->a(); };
}
If you need a spec quote:
The lambda-expression’s compound-statement yields the function-body ( 8.4 ) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions referring to non-static class members into class member access expressions using (*this) ( 9.3.1 ),
the compound-statement is considered in the context of the lambda-expression.
C++11. Lambdas member variable capture, this pointer pitfall in STL list
Don't capture this
if you are going to be copied. Whatever you capture, you are in charge of managing lifetime for.
Second, a pointer to the button being passed to the enter/leave makes lots of sense.
std::function<void(Button*)> on_mouse_enter;
std::function<void(Button*)> on_mouse_leave;
Then we have:
on_mouse_enter = [] (Button* but) {
but->square.set_color(1, 1, 1);
};
on_mouse_leave = [] (Button* but) {
but->square.set_color(0, 0, 0);
};
and the copy constructor no longer leaves you with pointers to a different this
.
Finally, when you call on_mouse_enter
, pass this
.
How to capture a single class data member in a lambda expression?
Using C++11 you will have to capture this
.
However, in C++14 you can capture arbitrary expressions, either by value:
[mBar1 = this->mBar1]() { ... }
or reference:
[&mBar1 = this->mBar1]() { ... }
Will C++0x support __stdcall or extern C capture-nothing lambdas?
Lambdas without a capture are implicitly convertible to a pointer to function (by a non-explicit conversion function defined by the closure type).
The FCD does not seem to specify what language linkage the function type of that function pointer type has, so if you need to pass this function pointer to C functions, the calling convention of C++ functions and C functions need to be the same. I believe that on Windows, that is the case though. So you should be able to pass the lambda to Windows API functions
typedef void(*callbackType)(void *userData);
extern "C" void someCFunction(callbackType callback);
int main() {
someCFunction([](void *userData) { /* ... */ });
}
FCD wording at 5.1.2/6
:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
I think the final Standard should have a note that says that there is a conversion function to both C linkage function pointers and C++ linkage function pointers, as convertibility to C function pointers is one of the goal of this functionality.
C++: Can an unused lambda explicit capture be optimized out?
The standard guarantees that captured values are not optimized away (per §5.1.2/14):
An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly
captured with a capture that does not include an &. For each entity captured by copy, an unnamed non-
static data member is declared in the closure type. The declaration order of these members is unspecified.
The type of such a data member is the type of the corresponding captured entity if the entity is not a
reference to an object, or the referenced type otherwise.
So, self
is copied into the closure on evaluation (per §5.1.2/21):
When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize
each corresponding non-static data member of the resulting closure object.
C++ lambda: how to 'freeze' values of local variables?
Here's a way:
#include <iostream>
#include <functional>
class A
{
double b;
public:
void set_b(double value) { b = value; }
std::function<double(double)> get_myFunction() const {
return [b = b] (double x) { return b*x; };
}
};
int main()
{
A myA;
myA.set_b(2.0);
std::function<double(double)> retrievedFunction = myA.get_myFunction();
myA.set_b(50.0);
std::cout << retrievedFunction(3.0) << '\n';
}
Crucial points:
Instead of creating a single
std::function
whenA
is constructed, we delay creation of the function untilget_myFunction
is called. Otherwise we'd only capture the (still uninitialized) value ofb
at the beginning.We explicitly capture
b
by value. We can't just say[b]
in the capture list because the outerb
isn't really a variable, it's just a member of*this
and any use ofb
really meansthis->b
. That's why[=]
doesn't work: It capturesthis
by value (which is just a pointer).The
[b = b]
syntax requires C++ 14.Another alternative would be
[*this]
, which captures a copy of the whole object. This requires C++ 17.
What is the best way to store historical data in SQL Server 2005/2008?
it DEPENDS on the applications usage patterns... If usage patterns indicate that the historical data will be queried more often than the current values, then put them all in one table... But if Historical queries are the exception, (or less than 10% of the queries), and the performance of the more common current value query will suffer from putting all data in one table, then it makes sense to separate that data into it's own table...
Why do lambda functions drop deduced return type reference by default?
I think the place you are stumbling is actually with the expression c.getObj()
in the line return c.getObj();
.
You think the expression c.getObj()
has type const Int&
. However that is not true; expressions never have reference type. As noted by Kerrek SB in comments, we sometimes talk about expressions as if they had reference type, as a shortcut to save on verbosity, but that leads to misconceptions so I think it is important to understand what is really going on.
The use of a reference type in a declaration (including as a return type as in getObj
's declaration) affects how the thing being declared is initialized, but once it is initialized, there is no longer any evidence that it was originally a reference.
Here is a simpler example:
int a; int &b = a; // 1
versus
int b; int &a = b; // 2
These two codes are exactly identical (except for the result of decltype(a)
or decltype(b)
which is a bit of a hack to the system). In both cases the expressions a
and b
both have type int
and value category "lvalue" and denote the same object. It's not the case that a
is the "real object" and b
is some sort of disguised pointer to a
. They are both on equal footing. It's one object with two names.
Going back to your code now: the expression c.getObj()
has exactly the same behaviour as c.m_obj
, apart from access rights. The type is Int
and the value category is "lvalue". The &
in the return type of getObj()
only dictates that this is an lvalue and it will also designate an object that already existed (approximately speaking).
So the deduced return type from return c.getObj();
is the same as it would be for return c.m_obj;
, which -- to be compatible with template type deduction, as mentioned elsewhere -- is not a reference type.
NB. If you understood this post you will also understand why I don't like the pedagogy of "references" being taught as "disguised pointers that auto dereference", which is somewhere between wrong and dangerous.
Related Topics
Difference Between Global Non-Throwing ::Operator New and Std::Malloc
C++ "Named Parameter Idiom" VS. Boost::Parameter Library
What Is Wrong with Making a Unit Test a Friend of the Class It Is Testing
How to Access a Global Variable Within a Local Scope
What Data Structure, Exactly, Are Deques in C++
How to Test If a Constexpr Function Is Evaluated at Compile Time
Print Template Typename at Compile Time
Why Can't I Put a Variable Declaration in the Test Portion of a While Loop
Testing If Given Number Is Integer
Using Std::Visit with Variadic Template Struct
Fast Implementation of Trigonometric Functions for C++
How to Build Openssl with Mingw in Windows
Typecasting Eigen::Vectorxd to Std::Vector
Lvalue to Rvalue Reference Binding
Sfinae and Partial Class Template Specializations