Lambda capture scope - c++

I'm struggling to understand the scope and ownership of lambda captures, why does the following code work?:
#include <iostream>
struct Foo {
void setCallback(std::function<void()> f) { callback = std::move(f); }
void trigger() { callback(); }
private:
std::function<void()> callback;
};
struct Bar {
int i;
Bar(int i) : i{i} { std::cout << "bar constructed" << std::endl; }
~Bar() { std::cout << "bar destroyed" << std::endl; }
};
int main() {
Foo foo{};
{ // scope
Bar bar{1};
foo.setCallback([&bar]() { std::cout << bar.i << std::endl; });
bar.i = 2;
} //end of scope, bar gets deleted
foo.trigger();
return 0;
}
Output:
bar constructed
bar destroyed
2
Is the compiler inlining bar.i in the lambda function statically? I'm capturing by reference, what is going on?

Hello Your code does not work because bar is descoped before the lambda that captured it is executed. The lambda uses a dangling reference. Here is an updated sample that will convince you, that if it works in your example it is simply because nothing else has been allocated at the address where bar was initially stored.
#include <iostream>
#include <functional>
struct Foo {
void setCallback(std::function<void()> f) { callback = std::move(f); }
void trigger() { callback(); }
private:
std::function<void()> callback;
};
struct Bar {
int i;
Bar(int i) : i{i} { std::cout << "bar constructed" << std::endl; }
~Bar() { std::cout << "bar destroyed" << std::endl; }
};
int main() {
Foo foo{};
{ // scope
Bar bar{1};
foo.setCallback([&bar]() { std::cout << bar.i << std::endl; });
bar.i = 2;
} //end of scope, bar gets deleted
volatile int a = 5; // allocate something after bar is destroyed
foo.trigger();
return 0;
}
Now you will get:
bar constructed
bar destroyed
5
5 is the next value allocated on the stack in place of bar.

Related

lambda expression using scope variables - is safe?

When f is called, a is already "destructed". Is it safe to use it this way? How does it work?
std::function<void()> f;
{
int a = some_calc();
f = [=] { std::cout << a << std::endl; }
}
f();
Is it safe to use it this way?
Yes
How does it work?
The closure object created by that lambda expression has int a as a data member, copy-initialised from the a in that scope.
Here is conceptually what is going on:
#include <functional>
#include <iostream>
int some_calc() {
// ...
return 42;
}
int main() {
std::function<void()> f;
{
int a = some_calc();
class Lambda {
private:
int a;
public:
Lambda(int const& _a) : a{_a} {}
void operator()() const { std::cout << a << std::endl; }
};
f = Lambda{a};
}
f();
}

Template variables with class as typename

I am learning C++14, in that come across this template variable feature and that interested me to dig more on this and i tried with multiple examples to understand the template variables. Say,
template <typename T>
T var;
var<int>;
var<float>;
Above code worked and it looked straight forward to understand too. But, when I tried to use class name in place of int or float as shown above, result in calling the temporary object creation for the class FOO and calling corresponding C'tor & dtor for the temp object.
var<FOO>; //FOO is a class
I have written a sample test program and its output for your understanding. My question is that,
Why var creates temp object?
How template variable differ for primitive datatypes and user defined datatypes?
If it is irrelevant or duplicate, please point me to the source for clear understanding.
Refer code below,
class B
{
public:
B()
{
std::cout<<"\nB ctor"<<std::endl;
}
B(const B& obj)
{
std::cout<<"B copy ctor"<<std::endl;
}
int operator()()
{
std::cout<<"operator() called"<<std::endl;
}
void f() {
//::A().print();
}
~B()
{
std::cout<<"\n~ for B()"<<std::endl;
}
};
//Declaring template variable
template<typename T>
T g ;
int main() {
g<int> = 30;
g<float> = 30.02f;
g<B> = B{};
std::cout<<"g value:"<<g<int><<std::endl;
std::cout<<"g value:"<<g<float>;
}
Output:
B ctor
g value:30
g value:30.02
~ for B()
No temporary object is created by this simple program:
int main() {
var<SomeClass>;
}
A temporary object is created here:
int main() {
var<SomeClass> = SomeClass{};
}
but that is because we did it with SomeClass{}. We then assigned that to the var<SomeClass> non-temporary object (global in many of your examples).
The code that runs here is
SomeClass::SomeClass()
SomeClass::SomeClass()
SomeClass::operator=(SomeClass&&)
SomeClass::~SomeClass()
SomeClass::~SomeClass()
in that order.
#include <iostream>
struct noisy {
noisy() { std::cout << __func__ << "()\n"; }
~noisy() { std::cout << __func__ << "()\n"; }
noisy(noisy&&) { std::cout << __func__ << "(&&)\n"; }
noisy(noisy const&) { std::cout << __func__ << "(c&)\n"; }
void operator=(noisy&&) { std::cout << __func__ << "(&&)\n"; }
void operator=(noisy const&) { std::cout << __func__ << "(c&)\n"; }
};
template<class T>
T var;
int main() {
std::cout << "Start of main\n";
{
var<noisy> = noisy{};
std::cout << "Body of main\n";
}
std::cout << "End of main\n";
}
live example.
Output:
noisy()
Start of main
noisy()
operator=(&&)
~noisy()
Body of main
End of main
~noisy()

How do you know which members are captured in a lambda with automatic capture?

When we write [=] or [&] in a lambda capture I'm just wondering how we can be sure exactly what it captures:
struct Bar
{
int memb;
int memb2;
int memb3;
};
std::function<void()> funcPtr;
void someFunc()
{
Bar bar;
Bar* barPtr = &bar;
funcPtr = [=]()
{
std::cout << barPtr->memb;
std::cout << barPtr->memb2;
std::cout << barPtr->memb3;
};
}
int main()
{
funcPtr();
}
Does the lambda capture three variables or just what is at the top, the pointer? If you specify the pointer in the lambda capture, use it, and then use its members does the lambda capture the members additionally?
void someFunc()
{
Bar* barPtr = new Bar;
funcPtr = [lambdaptr = barPtr]()
{ // lambdaptr is captured, what about the three members?
std::cout << lambdaptr;
std::cout << lambdaptr->memb;
std::cout << lambdaptr->memb2;
std::cout << lambdaptr->memb3;
};
}

class member unique pointer with custom deleter outside initializer list

class foo {
foo();
unique_ptr<T, (void *)(T*)> ptr;
};
foo::foo() {
bool x = some operation;
if (!x) throw;
ptr = unique_ptr<T, (void *)(T*)>(new T(x), deleter);
}
This code does not compile because the unique pointer and its deleter get initialized with null (as I don't initialize it in the initializer list). I can't initialize it in the list because it's dependent on the variable x as shown above. How can I solve this deadlock?
Try this:
foo()
: ptr(nullptr, deleter)
{
if (!some operation) { throw AppropriateException(); }
ptr.reset(new T(true));
}
One solution would be to add a static function that determines what x should be and then return it to the constructor of the unique_ptr in the member initialization list
foo() : ptr(construct_t(), deleter) {}
static T* construct_t()
{
bool x = some operation;
if(!x) throw;
return new T(x);
}
working example of using a generator and custom deleter:
#include <iostream>
#include <memory>
#include <vector>
struct bar {};
struct bar_deleter {
void operator()(bar* p) const noexcept {
try {
if (p) {
std::cout << "deleting p" << std::endl;
}
else {
std::cout << "not deleting p" << std::endl;
}
}
catch(...) {
}
}
};
bool some_condition()
{
static int counter = 0;
return (counter++ % 2) == 0;
}
struct foo {
using ptr_type = std::unique_ptr<bar, bar_deleter>;
foo()
: ptr(bar_generator())
{}
static ptr_type bar_generator() {
if (some_condition()) {
std::cout << "creating bar" << std::endl;
return { new bar, bar_deleter{} };
}
else {
std::cout << "not creating bar" << std::endl;
return { nullptr, bar_deleter{} };
}
}
ptr_type ptr;
};
int main()
{
using namespace std;
auto v = std::vector<foo>(10);
return 0;
}
expected results:
creating bar
not creating bar
creating bar
not creating bar
creating bar
not creating bar
creating bar
not creating bar
creating bar
not creating bar
deleting p
deleting p
deleting p
deleting p
deleting p

Delegating constructor issue - Is it safe?

This code is calling another ctor in one ctor:
#include <iostream>
using namespace std;
class F {
public:
F() { cout << "ctor1\n"; }
F(int) { cout << "ctor2\n"; }
~F() { cout << "dtor\n"; }
};
class Foo {
F f;
public:
Foo() : f() { cout << "1\n"; }
Foo(int i) : f(i) { Foo(); cout << "2\n"; }
};
int main() {
Foo object(1);
return 0;
}
The result is:
ctor2
ctor1
1
dtor
2
dtor
It seems the member variable f destroyed twice here, is it Okay?
Here
Foo(int i) { Foo(); cout << "2\n"; }
You are not using delegating constructor. What you're doing is creating a temporary instance of Foo in the constructor body (and destroying it immediately).
The correct syntax for delegating constructor is
Foo(int i) : Foo() { cout << "2\n"; }