When is 'this' captured in a lambda? - c++

I have a function in a class that defines a lambda and stores it in a local static variable:
class A
{
public:
void call_print()
{
static auto const print_func = [this] {
print();
};
print_func();
};
virtual void print()
{
std::cout << "A::print()\n";
}
};
class B : public A
{
public:
virtual void print() override
{
std::cout << "B::print()\n";
}
};
I also execute the following test:
int main()
{
A a;
B b;
a.call_print();
b.call_print();
}
(Live Sample)
What I expect to be printed is:
A::print()
B::print()
But what I really get is:
A::print()
A::print()
(Same object address is also printed with each)
I suspect this is due to the this capture. I assumed that it would capture the value of this when it is called, however it seems to be captured the moment the lambda is defined.
Could someone explain the semantics of lambda captures? When do they actually get provided to the function? Is it the same for all capture types, or is this a special case? Removing static fixes the problem, however in my production code I'm actually storing the lambda in a slightly-heavier object which represents a slot to which I insert into a signal later.

This has nothing to do with the semantics of lambda capture. It's simply how static works.
A static function-scoped variable is initialized exactly once. There is only ever one such object in your entire program. It will be initialized the first time the function is called (more specifically, the first time the static statement is executed). And therefore, the expression used to initialize the static variable is only ever invoked once.
So if a static function-scoped variable is initialized with data that's based on one of the function's parameters (like this), then it will only get the parameters from the first invocation of that function.
Your code creates a single lambda. It does not create different lambdas on each invocation of the function.
The behavior you seem to want is not a function-local static variable, but an object member. So just put a std::function object in the class itself, and have call_print initialize it if it is empty.

The lambda is instantiated the first time the enclosing function A::call_print() is called. Since the first time you call it on an A object, the this of that object is captured. If you reversed the order of invocation, you'd see a different result:
b.call_print();
a.call_print();
Output:
B::print()
B::print()
It more to do with the semantics of initialization of function-local static objects than those of lambda capture.

Static local variables are initialized the first time their declaration is executed.
In this case, you:
Create a lambda, capturing &A as this, that calls A.print();
Assign that lambda to print_func
Call that lambda (through print_func)
Call that lambda again.
Captured values are always captured when the lambda is created - which in this case is during the first call to call_print.

I don't think the capture is the problem here but the static keyword.
Think about your code as this:
class A
{
public:
void call_print()
{
static A* ptr = this;
ptr->print();
};
virtual void print()
{
std::cout << "A::print()\n";
}
};
class B : public A
{
public:
virtual void print() override
{
std::cout << "B::print()\n";
}
};
This is pretty much the same without a lambda.
If you look at the code it becomes pretty clear that your call a.call_print(); initializes ptr with a pointer to the object a which is then used further on.

This question is not so much about the behaviour of lambdas, but about the behaviour of static variables in functions.
The variable is created the first time code flows over it, using whatever variables are available at that time.
example:
#include <iostream>
int foo(int v)
{
static int value = v;
return v;
};
int main()
{
std::cout << foo(10) << std::endl;
std::cout << foo(11) << std::endl;
}
expected:
10
10
Because it's equivalent to:
foo::value = 10;
std::cout << foo::value << std::endl;
// foo::value = 11; (does not happen)
std::cout << foo::value << std::endl;

Indeed, the value of the capture is set when the lambda is defined, not when its called. Because you're setting a static variable to the expression that defines the lambda, this only happens the very first time the function call_print is called (by the rules governing static variables). Thus all call_print calls thereafter in fact get the same lambda, the one whose this is set to &a.

Related

Trying to return a function from a function with an argument function within it

I am curious if that's even possible to create a static function in another function and then return that static function with an argument function within it. So far what I've tried doesn't work at all, and when I use raw function pointers the code fails to compile.
#include <iostream>
#include <functional>
//both do not work but this one doesn't even compile
/*
void (*func(void (*foo)()))()
{
static void (*copy)();
copy = [&]() { foo(); };
return copy;
}
*/
std::function<void(void)> Foo(std::function<void(void)> func)
{
static std::function<void(void)> temp = [&]() { func(); };
return temp;
}
int main()
{
Foo([]() { std::cout << 123 << '\n'; });
}
The problem with your commented func is that a lambda which captures anything cannot convert to a pointer to function. Lambda captures provide data saved at initialization to be used when called, and a plain C++ function does not have any data other than its passed arguments. This capability is actually one of the big reasons std::function is helpful and we don't just use function pointers for what it does. std::function is more powerful than a function pointer.
Of course, func could instead just do copy = foo; or just return foo;, avoiding the lambda issue.
One problem with Foo is that the lambda captures function parameter func by reference, and then is called after Foo has returned and the lifetime of func has ended. A lambda which might be called after the scope of its captures is over should not capture them by reference, and std::function is an easy way to get into that bad situation. The lambda should use [=] or [func] instead.
Note that your static inside Foo is not like the static in front of an actual function declaration. It makes temp a function-static variable, which is initialized only the very first time and then kept. If Foo is called a second time with a different lambda, it will return the same thing it did the first time. If that's not what you want, just drop that static. Linkage of the functions/variables is not an issue here.
(It's a bit strange that Foo puts a std::function inside a lambda inside a std::function which all just directly call the next, instead of just using the original std::function. But I'll assume that's just because it's a simplified or learning-only example. If the lambda did something additional or different, this would be a fine way to do it.)
Your main ignores the function returned from Foo. Maybe you meant to call what Foo returns, with
int main()
{
Foo([]() { std::cout << 123 << '\n'; })();
}
It works, you simply never invoke the function:
#include <iostream>
#include <functional>
std::function<void(void)> Foo(std::function<void(void)> func)
{
static std::function<void(void)> temp = [&]() { func(); };
return temp;
}
int main()
{
// Notice final `()`
Foo([]() { std::cout << 123 << '\n'; })();
}
But you are capturing the function by reference, so you have to make sure the capturer doesn't outlive it.
Otherwise you could copy capture it.

Constructor parameter access member field of object under construction

I have the following structure that has a member function pointer. My question is, is there a way for the lambda that I pass to it to refer to its own member variable? i.e.
struct Foo
{
int aVar{1};
int (*funcPtr)(int);
Foo(int (*func)(int)) : funcPtr(func) {};
};
auto bar1 = Foo([](int a) {std::cout << a;}) // ok
auto bar2 = Foo([](int a) {std::cout << a + bar2.aVar;}) // Not ok but is there a way to access the member variable of the object currently being defined?
Can I achieve something to this effect?
What I would like to achieve here is a process to automatically generate objects based on the lambda you pass in. e.g: bar2 above is an object that can return anything plus its stored value. i.e. I would like bar2.funcPtr(5) == 5 + bar2.aVar to be an invariant of the class. In the future I might need another object that can return anything minus its stored value, and I only need to pass the corresponding lambda to do that (if the lambda can access the member fields), without defining a new class or method.
The lambda must have the signature int(int) but your lambda has the signature void(int) so that's the first problem.
The other is that the lambda must capture bar2. You could use std::function for that.
#include <iostream>
#include <functional>
struct Foo {
int aVar{1};
std::function<int(int)> funcPtr;
Foo(std::function<int(int)> func) : funcPtr(func) {};
int call(int x) { return funcPtr(x); }
};
int main() {
Foo bar2([&](int a) { return a + bar2.aVar; });
std::cout << bar2.call(2); // prints 3
}
A more practical solution would be to not tie the lambda to the instance for which it was originally created but to let it take a Foo& as an argument (and not to capture it). Moving it around doesn't become such a hassle with this approach.
Example:
struct Foo {
int aVar;
int(*funcPtr)(Foo&, int); // takes a Foo& as an argument
Foo(int x, int(*func)(Foo&, int)) : aVar(x), funcPtr(func) {};
int call(int x) { return funcPtr(*this, x); }
};
int main() {
Foo bar2(10, [](Foo& f, int a) { return a + f.aVar; });
std::cout << (bar2.call(5) == bar2.aVar + 5) << '\n'; // true
Foo bar3(20, [](Foo& f, int a) { return a * f.aVar; });
std::cout << bar2.call(2) << '\n'; // 10 + 2 = 12
std::cout << bar3.call(2) << '\n'; // 20 * 2 = 40
std::swap(bar2, bar3);
std::cout << bar2.call(2) << '\n'; // swapped, now 40
std::cout << bar3.call(2) << '\n'; // swapped, now 12
}
Foo( /* ... */ )
As used in the shown code this is a constructor call. This is constructing a new object, right there.
Before the new object can be created and its constructor get invoked, the parameters to the constructor must be evaluated. This is how C++ works. There are no alternatives, or workarounds, that end up constructing the object first and only then evaluate its constructor's parameters afterwards.
For this reason it is logically impossible for a lambda, that gets passed as parameter to the constructor, "refer to its own member variable". There is nothing in existence that has "its own member variable" at this point. The object's construction has not began, and you cannot refer to an object or a member of an object that does not exist. The object cannot be constructed until the constructor's parameters get evaluated, first. C++ does not work this way.
You will need to come up with some alternative mechanism for your class. At which point you will discover another fatal design flaw that dooms the shown approach:
int (*funcPtr)(int);
This is a plain function pointer. In order for lambda to reference an object that it's related to, in some form or fashion, it must capture the object (by reference, most likely). However lambdas that capture (by value or reference), cannot be converted to a plain function pointer. Only capture-less lambdas can be converted to a plain pointer.
At the bare minimum this must be a std::function, instead.
And now that it's a std::function, you can capture its object, by reference, in the lambda, and assign it to the std::function.
But this is not all, there is another problem that you must deal with: in order for all of this to work it is no longer possible for the object to be moved or copied in any way. This is because the lambda captured a reference to the original object that was constructed, full stop.
And the fact that the constructed object gets copied or moved does not, in some form or fashion, modify the lambda so it now magically captures the reference to the copy or the moved instance of the original object.
None of these are insurmountable problems, but they will require quite a bit of work to address, in order to have a well-formed C++ program as a result.

Why is the order of destruction same as order of construction, with static object (C++)?

The code is :
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
~A() { cout << "A::~" << endl; }
};
class B
{
public:
B() { cout << "B::B" << endl; }
~B() { cout << "B::~" << endl; }
};
int main()
{
B b;
static A a;
return 0;
}
The output is :
B::B
A::A
B::~
A::~
The scope of non-static object b and the scope of static object a ends at the end of main() function.
Question : Why is the order of constructors is same as the order of destructors ?
Static local variables will be destroyed at program exit.
The destructor for a block-scope static variable is called at program exit, but only if the initialization took place successfully.
So b will be destoryed firstly at the end of main(), a will be destroyed after that.
For the initialization,
are initialized the first time control passes through their declaration
So b will be initialized firstly in main(), then a gets initialized.
Because they have different lifespans. A is declared as function-local static variable.
Object created by declaration of automatic function-local variable got lifespan which begins before any use of that object and ends with the most nested code block (braces block) containing that declaration. In your case that's function main() body.
Object created by declaration of static function-local variable begins to exist after execution flow had entered the most nested code block containing that declaration and before any use of that object.
It got process-wide life span (stops to exist at std::atexit()), which happens after the function main() will be exited.
SO they are created in this particular case in order of declaration, but A will get destroyed way later. If your function was called twice, you'd see that B would be created twice but A only once. If function's flow would somehow omit either declaration, by if() statement or by returning early, the order of their creation of would change or both may be omitted.
It's implementation specific detail, but usually destruction of function-local statics implemented in same way as destruction of global objects, by call to a library function that lies under implementation of std::atexit, adding the address of destructor bound with value of pointer to object itself, but the execution may be concurrent (or may be not) with result of user's calls of std::atexit.
As addition to already existing answers, lets take a more phenomenological approach. Consider a small change on your example:
void foo() {
B b;
static A a;
}
int main() {
foo();
foo();
}
I assume you know that a is initialized only once and on the second call we get the exact same object a, because it is declared as static. Hence, it cannot be destroyed during or directly after the first call to foo. The expected first part of the output is
B::B // first call to foo()
A::A
B::~
B::B // second call to foo()
// no second call to A::A !
B::~
a can only be destroyed when your program terminates, otherwise you could not "reuse" it when calling the function again (thats why I had to modify the example, you cannot call main). As other answers explain in great detail, this happens after main returns. Hence last line of output will be
A::~

Why the `std::function` object(i.e `fn`) still works well after the object `ins` is out of scope?

Why the std::function object(i.e fn) still works well after the object ins is out of scope?
Here is the code snappit(https://godbolt.org/z/Y6KaWY):
#include <iostream>
#include <functional>
std::function<int(void)> fn;
class CTest
{
public:
CTest() {std::cout << "ctor:" << this << std::endl;};
int demo(void){std::cout << "this pointer:" << this << std::endl; return 0;}
};
void assign(void)
{
CTest ins;
fn = std::bind(&CTest::demo, &ins);
}
int foo()
{
return 9;
}
int main()
{
assign();
CTest tes1;
foo();
fn();
}
The outputs:
Program returned: 0
Program stdout
ctor:0x7fff64960a80
ctor:0x7fff64960be0
this pointer:0x7fff64960a80 //You see, still point to the object(i.e `ins`) that is out of its scope
The class CTest has no data members and no virtual methods. When you capture its address (&ins) with std::bind, you store it inside an instance that is assigned to the global variable fn. When you execute CTest::demo() through fn you are passing the captured pointer to the method demo() as the first parameter (this). You are not accessing any members of the class CTest. This is all valid. But since you don't know what the user of fn will do with the stored pointer, that is going to become invalid at the end of assign(), this is classified as undefined behavior.
If you add members to CTest and try to access them from CTest::demo(), then you will be accessing memory that this pointer points to, but that memory is no longer valid and may have been overwritten.
If you add a virtual method and try to execute it from CTest::demo() or even if you make CTest::demo() virtual, you will most likely call invalid functions, because the pointer to the virtual method table is part of the memory that the captured pointer points to and may have been overwritten.

Is it safe to change a function pointer (std::function) inside a called function?

I have a std::function pointing to a function. Inside this function I change the pointer to another function.
std::function<void()> fun;
void foo() {
std::cout << "foo\n";
}
void bar() {
std::cout << "bar\n";
fun = foo;
}
int main() {
fun = bar;
fun();
fun();
}
I can't see any problem and it works just fine (see here), however I'm not sure if this is legal to do so. Is there anything I am missing? Maybe in the c++ standard draft (I checked quickly but didn't see anything so far).
This is legal with function pointers.
When you assign or construct a std::function with a target, it creates a copy of the target. In the case of assigning a function to the std::function, this in effect stores a function pointer as the target object.
When you invoke operator(), it is required to return what would happen if you invoked that the target with the arguments.
Within that "body" of the copy of the function object stored as a copy in the std::function, if you reassign to the std::function, this destroys the old target function object.
Destroying a function pointer has no impact on the validity of code executed within the function pointed to.
However, if you had stored function objects (lambdas, manual ones, other std::functions, std::bind, etc), at the point of assignment you'd run into the usual rules of running a method in a class when this is destroyed. In short, you would no longer be able to do anything that relied on "local state" of your instance.
std::function<void()> fun;
struct bob {
std::string name;
bob* next = 0;
void operator()() const {
std::cout << name << "\n";
if (next) fun = *next;
// undefined behavior:
// std::cout << name << "\n";
}
};
bob foo = {"foo"};
bob bar = {"bar", &foo};
int main() {
fun = bar;
fun();
fun();
}
live example.
So as you can see, this can be fragile.
It may come back to bite you if you do it without due consideration and in code documentation, but there is no logical reason why it won't work.
In c++, the address of a function is not needed, either within the function in the return coding.
If it didn't work in some language the complier probably wouldn't accept it - if it's a half decent compiler.