I see the C++11 documentation (http://en.cppreference.com/w/cpp/language/lambda) for lambda expressions states capture by value and reference are supported but not rvalue reference. The closest SO question I could find related to this is: How to capture a unique_ptr into a lambda expression?, but it seems like my use case doesn't require the use of std::bind.
Code
#include <iostream>
#include <memory>
class Foo
{
public:
explicit Foo(int value = 0) : mValue(value) {}
// The following items are provided just to be explicit
Foo(Foo &&other) = default;
Foo &operator=(Foo &&other) = default;
Foo(const Foo &other) = delete;
Foo &operator=(const Foo &other) = delete;
~Foo() {}
int mValue;
};
void bar(std::unique_ptr<Foo> f)
{
std::cout << "bar: " << std::dec << f->mValue << "\n";
}
int main()
{
{
std::unique_ptr<Foo> f(new Foo(22));
std::cout << "main: " << std::hex << f.get() << "\n";
// Call the bar function directly (requires using std::move)
bar(std::move(f));
std::cout << "main: " << std::hex << f.get() << "\n";
}
{
std::unique_ptr<Foo> f(new Foo(99));
std::cout << "main: " << std::hex << f.get() << "\n";
// Lamda expression captures 'f' by reference and then calls the bar function (again, requires using std::move)
auto fn = [&f](){ bar(std::move(f)); };
fn(); // Execute the closure
std::cout << "main: " << std::hex << f.get() << "\n";
}
return 0;
}
Example Output
main: 0x92e010
bar: 22
main: 0
main: 0x92e010
bar: 99
main: 0
By examining the output it appears this program is running correctly (i.e., the observed results are what I expected. However, I have the following questions.
Questions
Is using the closure equivalent to the code that calls the bar function directly?
I'm asking explicitly since the documentation (see beginning of the question) about lambda expressions didn't state anything about using std::move on captured references (i.e., I want to make sure this doesn't run afoul of undefined behavior or similar bad outcomes).
If the answer to the first question is "you can't use std::move on the captured reference", then what is the right way to do this (e.g., the std::bind solution, etc)?
Is using the closure equivalent to the code that calls the bar function directly?
Yes, they're equivalent in this code. Captured references aren't special in any way that I can think of: you have fully defined behavior, as long as f is in scope and can be moved from.
Related
I am having the below code :
std::vector<std::function<void()>> functors;
class Bar
{
public :
Bar(const int x, const int y):d_x(x),d_y(y){}
~Bar(){
cout << "Destructing Bar" << endl;
}
void addToQueue()
{
const auto job = [=](){
cout << "x:" << d_x << " y: " << d_y;
};
functors.push_back(job);
}
private :
int d_x,d_y;
};
void example()
{
cout << "Hello World" << endl;
{
shared_ptr<Bar> barPtr = make_shared<Bar>(5,10);
barPtr->addToQueue();
}
cout << "Out of scope. Sleeping" << endl;
usleep(1000);
functors[0]();
}
The output is as expected :
Hello World
Destructing Bar
Out of scope. Sleeping
x:5 y: 10
I am now capturing by value, which is why I assume when the Bar object gets destroyed, I can still access its member variables. If the above is right, I am expecting the below change to give me UB:
const auto job = [&](){
However, I still see the same result. Why is that? Have i understood something wrong?
EDIT Further on the above, what I want to understand from this example - is how can I have access to a class member variables in a lambda function even if object has been destroyed? I am trying to avoid UB and thought that passing by value is the way to go, but can't prove that the opposite isn't working.
This kind of confusion iss probably one of the reasons why C++20 deprecated the implicit capture of this with [=]. You can still capture [this], in which case you have the usual lifetime issues with an unmanaged pointer. You can capture [*this] (since C+=17), which will capture a copy of *this so you don't have lifetime issues.
You could also use std::enable_shared_from_this since you're using a std::shared_ptr in example, but that's a bit more complicated. Still, it would avoid both the copy and the UB when the lifetime issues.
In these examples you are capturing this and not any of the fields.
When capturing this, by design, it is never captured by copying the object or the fields.
The best way to capture a field by value is:
[field = field] () { }
Both versions of your code have undefined behaviour. barPtr is the only owner of the shared_ptr so your object is destructed at the end of the scope containing barPtr. Executing the lambda which has captured this from the object in barPtr has undefined behaviour.
The usual way to prevent this is for the lambda to capture a shared_pointer from shared_from_this to keep the object alive. E.g:
#include <vector>
#include <functional>
#include <iostream>
#include <memory>
std::vector<std::function<void()>> functors;
class Bar : public std::enable_shared_from_this<Bar>
{
public :
Bar(const int x, const int y):d_x(x),d_y(y){}
~Bar(){
std::cout << "Destructing Bar\n";
}
void addToQueue()
{
auto self = shared_from_this();
const auto job = [this, self](){
std::cout << "x:" << d_x << " y: " << d_y << "\n";
};
functors.push_back(job);
}
private :
int d_x,d_y;
};
int main()
{
std::cout << "Hello World\n";
{
std::shared_ptr<Bar> barPtr = std::make_shared<Bar>(5,10);
barPtr->addToQueue();
}
std::cout << "Out of scope\n";
functors[0]();
}
By capturing self the shared_ptr will now survive for at least as long as the lambda does.
I don't know there is std::addressof available in c++ standard library until today I read some blog. In my understanding, if opeartor & is overloaded, then std::addressof should be used, otherwise it's not necessary to use std::addressof, it should be equivalent with &.
However, just trying to use std::addressof, to validate if it is the same as &, I meet compile error: "call to deleted function 'addressof' ". Don't know why.
Here's the minimal code to demonstrate this problem:
#include <iostream>
#include <memory>
class Foo
{
public:
Foo(int _len): len(_len) {
if(len>0) {
data = new double[len];
}
// compile error: call to deleted function 'addressof'
std::cout << "Foo() " << std::addressof(this) << "/" << std::addressof(data) << std::endl;
}
~Foo() {
// compile ok
std::cout << "~Foo() " << (void*)this << "/" << (void*)data << std::endl;
// compile error: call to deleted function 'addressof'
std::cout << "~Foo() " << std::addressof(this) << "/" << std::addressof(data) << std::endl;
if (data!=nullptr) {
delete[] data;
}
}
private:
int len;
double* data;
};
int main() {
Foo(42);
return 0;
}
C++ standard:
ยง9.3.2 The this pointer
the keyword this is a prvalue expression
std::addressof
template <class T>
const T* addressof(const T&&) = delete;
So addressof overload for rvalues is deleted. The reason is because you cannot take the address of a prvalue so addressof is modeled to respect that.
That's why you get the error.
Please note that addressof(this) and (void*) this are not even in the same ballpark. The equivalent of addressof(this) would be &this which also doesn't compile.
The following code is also available at godbolt.org/z/SjkAWZ.
I have a struct with a std::function as member variable, which gets assigned by a lambda expression in the constructor.
The lambda can be called from the constructor successfully, but not from a member function.
#include <vector>
#include <functional>
struct S
{
S()
{
std::cout << "construct: " << reinterpret_cast<long>(this) << " " << std::flush;
std::cout << m_ << '\n';
lambda_ = [&]() {
std::cout << "lambda: " << reinterpret_cast<long>(this) << " " << std::flush;
std::cout << m_ << '\n';
};
lambda_();
}
void foo()
{
std::cout << "foo: " << reinterpret_cast<long>(this) << " " << std::flush;
std::cout << m_ << '\n';
lambda_();
}
private:
int m_ = 3; // some member variable
std::function<void(void)> lambda_;
};
int main()
{
std::vector<S> v;
v.emplace_back();
v.emplace_back();
std::cout << "\n--- loop ---\n";
for(auto& b : v)
{ b.foo(); }
}
Possible program output:
construct: 94159000759920 3
lambda: 94159000759920 3
construct: 94159000761048 3
lambda: 94159000761048 3
--- loop ---
foo: 94159000761008 3
lambda: 94159000759920 0 // <-- bad *this* address, bad value for m_
foo: 94159000761048 3
lambda: 94159000761048 3 // <-- bad *this* address, correct value for m_ (coincidence?)
As you can see, the context this of the lambda function is wrong if it gets called from the member function foo.
Interestingly, this is not the case if I only emplace one element in the vector:
construct: 13753968 3
lambda: 13753968 3
--- loop ---
foo: 13753968 3
lambda: 13753968 3 // <-- correct *this* address and correct value for m_
I am using g++ version 8.3.0 on Debian.
Am I causing undefined behaviour by constructing the elements in the vector in place?
You missed the copy / move constructor for your struct!
If you assign some vars to a std::vector it will reserve sometimes new memory and copy all content to the new memory. In your case, the lambda is not aware about the change and keeps the reference to the old instance of S. So your code is simply broken.
You can work around the problem by reserving enough space before you assign content with:
int main()
{
std::vector<S> v;
v.reserve(5);
...
}
But this is only a work around! You should prepare a move/copy constructor to be able to get correct copies of your instances.
I would like to use lambdas to conditionally expand the functionality of a function within a class. There is no problem doing this outside of the class scope (see example), but the minimal working example below leads to a segmentation fault when calling a function that has modified itself within the class. Can anyone explain why this code fails and how I should be thinking about lambdas within a class differently than lambdas outside of a class?
#include <functional>
#include <iostream>
class MyClass
{
public:
MyClass(bool modify);
int a;
std::function<void (void)> myFunc;
};
MyClass::MyClass(bool modify)
{
a = 2;
myFunc = [this](){ std::cout << "1. Inside my initialized function; a="
<< this->a << std::endl;};
//myFunc(); -- works with or without being commented
if (modify)
{
myFunc = [this](){ this->myFunc();
std::cout << "2. adding an output line to my "
<< "initialized function" << std::endl;};
//EDIT: Originally tried
// myFunc = [myFunc](){ myFunc(); std::cout << endl; };
// but this will not compile. See edit of post below
//myFunc(); -- fails with or without being commented
}
}
int main(int argc, char **argv)
{
std::function<void (void)> func;
int a = 2;
func = [a](){ std::cout << "1. Inside my initialized function; a="
<< a << std::endl;};
func = [func](){ func();
std::cout << "2. adding an output line to my initialized "
<< "function" << std::endl;};
std::cout << "Result of modified function outside of class: " << std::endl;
func();
std::cout << std::endl;
std::cout << "Result of unmodified function in class: " << std::endl;
MyClass myClassNoMod(false);
myClassNoMod.myFunc();
std::cout << std::endl;
std::cout << "Result of modified function in class: " << std::endl;
MyClass myClassMod(true);
myClassMod.myFunc();
return 0;
}
Edit PaulR gave the reasonable suggestion of capturing myFunc rather than this in the update of myFunc. In my original implementation this is what I tried:
myFunc = [myFunc](){myFunc(); std::out << "stuff\n"; };
but this lead to the compiler errors
error: 'myFunc' in capture list does not name a variable
myFunc = [myFunc](){ myFunc();
^
error: 'this' cannot be implicitly captured in this context
myFunc = [myFunc](){ myFunc();
In your class you capture the this pointer and not the previous value of myFunc, thus your lambda will recursively call itself forever, since at call time the myFunc member will be already changed to the new lambda.
In main you capture the previous value of func by value and thus it does what you expect.
So I would suggest capturing a copy of myFunc by value (i.e. without &) instead of this.
if (modify)
{
auto previousFunc = std::move(myFunc);
myFunc = [previousFunc](){ previousFunc();
std::cout << "2. adding an output line to my "
<< "initialized function" << std::endl;};
}
If you are using C++14 or newer you can also use lambda capture expressions to avoid making a copy and directly moving the previous function into the lambda capture:
if (modify)
{
myFunc = [previousFunc{std::move(myFunc)}](){ previousFunc();
std::cout << "2. adding an output line to my "
<< "initialized function" << std::endl;};
}
So I have a perfect forwarder, and I want to appropriately capture it in a lambda, such that R-values are copied in, and L-values are captured by reference. However simply using std::forward doesn't do the job, as evidenced by this code:
#include<iostream>
class testClass
{
public:
testClass() = default;
testClass( const testClass & other ) { std::cout << "COPY C" << std::endl; }
testClass & operator=(const testClass & other ) { std::cout << "COPY A" << std::endl; }
};
template< class T>
void testFunc(T && t)
{ [test = std::forward<T>(t)](){}(); }
int main()
{
testClass x;
std::cout << "PLEASE NO COPY" << std::endl;
testFunc(x);
std::cout << "DONE" << std::endl;
std::cout << "COPY HERE" << std::endl;
testFunc(testClass());
std::cout << "DONE" << std::endl;
}
Compiling this with
g++ -std=c++14 main.cpp
Produces the output
PLEASE NO COPY
COPY C
DONE
COPY HERE
COPY C
DONE
In a perfect world, I would like to only have the "COPY C" appear in the rvalue case, not the lvalue case.
My work around would be to use a helper function overloaded for L- and R- values, but I was wondering if there was a better way.
Cheers!
You may use the following:
[test = std::conditional_t<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<std::remove_reference_t<T>>,
T>{std::forward<T>(t)}]
Live Demo
but providing helper function seems more readable