C++11 Lambdas: Member Variable Capture Gotcha

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 when A is constructed, we delay creation of the function until get_myFunction is called. Otherwise we'd only capture the (still uninitialized) value of b at the beginning.

  • We explicitly capture b by value. We can't just say [b] in the capture list because the outer b isn't really a variable, it's just a member of *this and any use of b really means this->b. That's why [=] doesn't work: It captures this 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



Leave a reply



Submit