I am trying to write a lambda that receives a temporary object.
The lambda will be cached for later execution, and will be executed after the original object was destructed (hence should make a copy if it).
Main points:
Define class
Xthat implements move semantics, but disable copy-c'tor and assignment op,Define function
foo(X x)that receives this type,Create lambda
l, and store it general function-pointer typestd::function<void()>, for later execution. We will call this function-pointerf,After original
xwas destructed, executef.
I did not manage to write this lambda.
I know I can solve this easily using pointer to object instead of object, but I want to learn whether it is possible to use the object directly, assuming I implemented all move semantics correctly.
Code example (which does not work correctly):
#include <iostream>
#include <string>
#include <functional>
class X
{
private:
std::string m_s;
public:
X(){}
X(X&& other)
{ m_s = std::move(other.m_s);}
~X()
{ m_s = "Object destructed...";}
X& operator=(X&& other)
{ m_s = std::move(other.m_s); return *this;}
void SetString(const char* s)
{ m_s = s;}
void Print() const
{ ::printf("X::Print() - String value: '%s'\n", m_s.c_str());}
private:
X(const X&) = delete;
X& operator=(const X&) = delete;
};
void foo(X x)
{ x.Print();}
// Predefined lambda:
auto l = [](X x){ foo(std::move(x));};
int main()
{
std::function<void()> f = nullptr;
// Create temporary scope for 'x' to verify object
// destruction happens before 'f' is called:
{
X x;
x.SetString("Hello World!");
f = [&](){ l(std::move(x));};
}
// Expecting to see 'Hello World!'
f();
return 0;
}
OK, I've got my head around this now so I've rewritten my answer. There's no way to make this work with
xdeclared on the stack because how ever much moving you do, the parameter passed tofoowill have been destroyed by the time the lambda actually executes.Instead (and it's obvious, once you see it),
xhas to be dynamically allocated as this is the only way to manage its lifetime. Given that observation, it becomes clear how to pass it around: there's a smart pointer for that, it's copyable (deliberately) and it's calledstd::shared_ptr. So here's code that works correctly:Output:
Live demo (Wandbox appears to be broken :( )
And OP, if you post what you claim is a MRE, please:
make sure it compiles
include all the relevant
#includesinclude all the relevant code (where are the [deleted] copy and [implemented] move constructors / operators?)
The first part of the question (which, on reflection, I agree you need to keep) should also be distilled down into a single code fragment. Thank you.