Using C++11 lambdas asynchronously, safely - c++

I've come to C++11 from an Objective-C background, and one thing I'm struggling to come to terms with is the different capturing semantics of C++11 lambdas vs Objective-C "blocks". (See here for a comparison).
In Objective-C, like C++, the self/this pointer is implicitly captured if you refer to a member variable. But because all objects in Objective-C are effectively "shared pointers", to use the C++ terminology, you can do this:
doSomethingAsynchronously(^{
someMember_ = 42;
});
... and you're guaranteed that the object whose member you're accessing will be alive when the block executes. You don't have to think about it. The equivalent in C++ seems to be something like:
// I'm assuming here that `this` derives from std::enable_shared_from_this and
// is already owned by some shared_ptr.
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis, this] {
someMember_ = 42; // safe, as the lambda holds a reference to this
// via shared_ptr.
});
Here, you need to remember to capture the shared_ptr in addition to the this pointer. Is there some less error-prone way of achieving this?

One of the founding principles of C++ is that you don't pay for what you don't use. That means in this case that contexts where taking a shared_ptr to this is unnecessary shouldn't incur any reference counting overhead. This also means that it shouldn't happen automatically even e.g. as a feature of enable_shared_from_this, since you might want to pass a short-lived lambda to an algorithm (for_each, etc.) in which case the lambda doesn't outlive its scope.
I'd suggest adapting the lambda-wrapper pattern; in that case it's used for move capture of a large object (How to capture std::unique_ptr "by move" for a lambda in std::for_each), but it can equally be used for shared capture of this:
template<typename T, typename F>
class shared_this_lambda {
std::shared_ptr<T> t; // just for lifetime
F f;
public:
shared_this_lambda(std::shared_ptr<T> t, F f): t(t), f(f) {}
template<class... Args>
auto operator()(Args &&...args)
-> decltype(this->f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
};
template<typename T>
struct enable_shared_this_lambda {
static_assert(std::is_base_of<std::enable_shared_from_this<T>, T>::value,
"T must inherit enable_shared_from_this<T>");
template<typename F>
auto make_shared_this_lambda(F f) -> shared_this_lambda<T, F> {
return shared_this_lambda<T, F>(
static_cast<T *>(this)->shared_from_this(), f);
}
template<typename F>
auto make_shared_this_lambda(F f) const -> shared_this_lambda<const T, F> {
return shared_this_lambda<const T, F>(
static_cast<const T *>(this)->shared_from_this(), f);
}
};
Use by inheriting enable_shared_this_lambda in addition to enable_shared_from_this; you can then explicitly request that any long-lived lambdas take a shared this:
doSomethingAsynchronously(make_shared_this_lambda([this] {
someMember_ = 42;
}));

Boost uses:
auto self(shared_from_this());
auto l = [this, self] { do(); };
Mentioned here: What's the reason of using auto self(shared_from_this()) variable in lambda function?

Actually, there's one right answer to this problem. The answer has the exact same effect of binding with shared_from_this() (like when you do it with boost::asio::io_service). Think about it; what does binding with shared_from_this() do? It simple replaces this. So what prevents you from replacing this with shared_from_this() totally?
Following your example, which I updated to make the difference clearer, instead of this:
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis, this] () {
this->someMember_ = 42; //here, you're using `this`... that's wrong!
});
Do this:
auto strongThis = shared_from_this();
doSomethingAsynchronously([strongThis] () //notice, you're not passing `this`!
{
strongThis->someMember_ = 42;
});
The only cost here is that you're gonna have to prefix everything with strongThis->. But this is the most meaningful way to do it.

Related

Get a reference to the lambda's captured value

I am using a function (not mine, from a library I don't control) with a signature similar to this:
template<typename T, typename F>
void do_async(T const&, F); // the second parameter is a callable
and it usually used like this
do_async(obj, [this](){ ... });
I wrote a function similar to this that always uses the same callback lambda:
template<typename T>
void do_async_wrapper(T obj) {
do_async(obj, [this](){ ... });
}
My problems stem from the fact that since the obj is passed as a reference, it has to be kept alive until the callback is called. My function is supposed to take care of that so the caller doesn't have to worry about object lifetime. That is why it accepts by value.
I would like to do something like this in order to keep it alive:
template<typename T>
void do_async_wrapper(T obj) {
do_async(obj, [this, obj{std::move(obj)}](){ ... });
}
Obviously this wont (always) work as-is since the reference points to the function-local one which doesn't exist anymore, while the one kept alive is a (move-)copy of it.
Any suggestions?
As the functor is taken by value, you cannot store the object directly in the functor and pass a reference to it.
You may work-around that by using smart pointer as shared_ptr:
template<typename T>
void do_async_wrapper(T obj) {
auto ptr = std::make_shared<T>(std::move(obj));
do_async(*ptr, [this, ptr](){ /*...*/ });
}

return lambda by rvalue ref?

#include <iostream>
#include <functional>
template <typename... Args>
std::function<void(Args...)> pushToEventLoop(std::function<void(Args...)> && p_function)
{
auto func = [p_function](Args... args) ->void
{
// This is what i would do here, but requires too much source code
//ThreadPool::enque(std::bind(p_function, args...));
// This is what i'll do for the sake of the example.
p_function(args...);
};
return func;
}
int main()
{
auto function(pushToEventLoop(std::function<void(char const *)>(std::bind(std::printf, std::placeholders::_1))));
auto function2 = std::bind(function, "Hello World!\n");
function2();
return 0;
}
Is it possible and how, to return the "func" variable by rvalue ref?
I have a feeling that this is somehow totally insane, but I'd like to know why, so I can restore my sanity.
I have no idea if i have done something horribly wrong. Please provide feedback.
I built this thing so that I can make callbacks that are actually just posted to the treadpool for processing, without the caller or the target knowing anything about this. The middleman that binds them together makes the choice of how to connect them.
https://ideone.com/4Wfhb1
EDIT
Ok, so I thought that there is copying going on when I return the func variable. But apparently it's dealt with by RVO, so no copying takes place. I have not verified this, but now that I think about it, that would make sense.
If your question is how to return a lamba in the most eficient way, then just return it by value and use automatic return typ deduction:
//this will actually return a lmabda and not a std::function
template <typename... Args>
auto pushToEventLoop(std::function<void(Args...)> && p_function)
{
return [f = std::move(p_function)](Args... args)
{
f(args...);
};
}
This will leverage RVO and avoid any dynamic memory allocations that std::function might have to perform.
Also having an r-value reference parameter usually doesn't gain you anything, if you don't move from it (unless you require that specific interface for another reason). In order to do so here you can leverage c++14's generalized lambda capture (the compiler can't perform that optimization by itself, as p_function itself is an l-value).
Now, if your question on the other hand was, if/how you can return a (r- or l-value) reference to a non-static local variable from a function, then the answer is simply:
NEVER DO THAT!
I think what you're trying to do is to move p_function into your lambda while avoiding copies? Presumably this is for performance reasons?
In which case you probably want to write it like this:
template <typename... Args>
// return by value - because RVO will elide copies for us
std::function<void(Args...)>
// passing by r-value reference... ok no problem there
pushToEventLoop(std::function<void(Args...)> && p_function)
{
// but I want to MOVE my p_function into func
// this will require at least c++1y (c++14)
auto func = [p_function = std::move(p_function)](Args... args) ->void
{
// p_function has now been moved into the lambda ...
};
// ... p_function passed to us is now in a valid but undefined state
// so don't use it here
// allow RVO to do its thing
return func;
}

Extending lifetime of temporary - proper way

Say I have:
f(T& t){ ... }
which I sometimes want to provide argument for from a function call
T GetT() { ... }
like this:
f(GetT())
Which won't compile even though I'm convinced that the lifetime of T is guaranteed to last until the end of expression, I also cannot change the T& to const T& because I need to modify the object inside f.
I thought about using T&& but then when I happen to have lvalue of T I would need to move() it, which would make it awkward because I sometimes need to use T after the call to f. In my case T is plain old data so I guess it would work but it doesn't feel right to move an object and use it afterwards.
Is there an elegant way to allow function to take both rval and lval refs to mutable object?
ATM I'm just doing
T t = GetT();
f(t);
Which I feel is at least one useless line and one useless copy of T.
How about using universal references.
Not sure if you would consider it elegant but it would look something like this:
struct MyStruct
{
int i;
};
template<class T>
void foo(T&& t)
{
static_assert(std::is_base_of<MyStruct,
typename std::remove_reference<T>::type>::value, "ERROR");
t.i = 1024;
}
MyStruct GetMyStruct()
{
return MyStruct();
}
int main()
{
foo(GetMyStruct());
MyStruct ms;
foo(ms);
return 0;
}
The way that you're currently doing, i.e. storing the object in a variable, is a proper way to extend the lifetime of the returned object and allow non-const references to bind to it. If GetT is implemented so that (N)RVO is possible, then no useless copy need to be made because it can be elided.
I came up with a solution to my problem with simple overload:
f(T& t) { ... }
f(T&& t) { f(t); }
But there still has to be a better way.
You cannot bind a reference to a temporany: only const reference can do that.
I suggesto you to look this link C++11 binding rules for const &&

How C++11 threads are wrapped around pthreads

So C++11 threads are wrappers around pthreads on most systems, I am confused how the syntax for going from a variadic function to a more strict function with a specified return type might work (i.e. the callback function with pthreads) can someone give an example that could illustrate the same?
Suppose you have a C style interface that looks like:
Foo run( Foo(*)(void*), void* );
And you want to write:
template<class F, class...Args>
std::result_of<F(Args...)>
smart_run( F&& f, Args&&... args );
This is analogous to what you need to do to implement std::thread on top of pthreads. I simplified stuff a bit, because it is noise (no std ref support, no decaying, etc).
For the first step, take F and Args... and bind them up. Something like std::bind(f, args...) that returns a zero-arg function that returns the result.
With that, we just need to solve:
template<class F>
std::result_of<F()>
smart_run( F&& f );
which takes an arbitrary callable, then uses run above to run it.
The trick is to create a copy of f on the free store and a function that calls it like this:
template<class F>
std::result_of<F()>
smart_run( F&& f ){
struct data{
F f;
std::result_of_t<F()> r;
};
data*p = new data{std::forward<F>(f)};
Foo ignored=run(
[](void* p){
data* self=static_cast<data*>(p);
auto& f=self->f;
self->r = f();
return Foo{}; // whatever
},
p
);
auto r=data->r;
delete data;
return r;
}
Now, the r is assigned instead of constructed. But the core of the idea -- that you pass the fancy callable in the void*, andmthe function unwraps it and interacts with it, and done is there.
In a real thread on pthread, you'd pass a pointer-to-std::thread-state to the pthread invoker. It would set whatever up, invoke the stored procedure, and when done would take the return value and store it in the internal std::thread state (if needed). Then you could get that data by interacting with the internal std::thread state.
Or something else roughly equivalent.

How to capture a unique_ptr into a lambda expression?

I have tried the following:
std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
//The caller given ownership of psomething
return [psomething](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
But it does not compile. Any ideas?
UPDATE:
AS suggested, some new syntax is required to explicitly specify we need to transfer the ownership to the lambda, I am now thinking about the following syntax:
std::function<void ()> getAction(std::unique_ptr<MyClass> psomething){
//The caller given ownership of psomething
return [auto psomething=move(psomething)](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
Would it be a good candidate?
UPDATE 1:
I will show my implementation of move and copy as following:
template<typename T>
T copy(const T &t) {
return t;
}
//process lvalue references
template<typename T>
T move(T &t) {
return std::move(t);
}
class A{/*...*/};
void test(A &&a);
int main(int, char **){
A a;
test(copy(a)); //OK, copied
test(move(a)); //OK, moved
test(A()); //OK, temporary object
test(copy(A())); //OK, copying temporary object
//You can disable this behavior by letting copy accepts T &
//test(move(A())); You should never move a temporary object
//It is not good to have a rvalue version of move.
//test(a); forbidden, you have to say weather you want to copy or move
//from a lvalue reference.
}
This issue is addressed by lambda generalized capture in C++14:
// a unique_ptr is move-only
auto u = make_unique<some_type>(some, parameters);
// move the unique_ptr into the lambda
go.run([u = move(u)]{do_something_with(u);});
You cannot permanently capture a unique_ptr in a lambda. Indeed, if you want to permanently capture anything in a lambda, it must be copyable; merely movable is insufficient.
This could be considered a defect in C++11, but you would need some syntax to explicitly say that you wanted to move the unique_ptr value into the lambda. The C++11 specification is very carefully worded to prevent implicit moves on named variables; that's why std::move exists, and this is a good thing.
To do what you want will require either using std::bind (which would be semi-convoluted, requiring a short sequence of binds) or just returning a regular old object.
Also, never take unique_ptr by &&, unless you are actually writing its move constructor. Just take it by value; the only way a user can provide it by value is with a std::move. Indeed, it's generally a good idea to never take anything by &&, unless you're writing the move constructor/assignment operator (or implementing a forwarding function).
The "semi-convoluted" solution using std::bind as mentioned by Nicol Bolas is not so bad after all:
std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething)
{
return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); },
std::move(psomething));
}
A sub-optimal solution that worked for me was to convert the unique_ptr to a shared_ptr and then capture the shared_ptr in the lambda.
std::function<void()> getAction(std::unique_ptr<MyClass> psomething)
{
//The caller given ownership of psomething
std::shared_ptr<MyClass> psomethingShared = std::shared_ptr<MyClass>(std::move(psomething));
return [psomethingShared]()
{
psomethingShared->do_some_thing();
};
}
I used this really dodgy workaround, which involves sticking the unique_ptr inside a shared_ptr. This is because my code required a unique_ptr (due to an API restriction) so I couldn't actually convert it to a shared_ptr (otherwise I'd never be able to get my unique_ptr back).
My justification for using this abomination is that it was for my test code, and I had to std::bind a unique_ptr into the test function call.
// Put unique_ptr inside a shared_ptr
auto sh = std::make_shared<std::unique_ptr<Type>>(std::move(unique));
std::function<void()> fnTest = std::bind([this, sh, input, output]() {
// Move unique_ptr back out of shared_ptr
auto unique = std::move(*sh.get());
// Make sure unique_ptr is still valid
assert(unique);
// Move unique_ptr over to final function while calling it
this->run_test(std::move(unique), input, output);
});
Now calling fnTest() will call run_test() while passing the unique_ptr to it. Calling fnTest() a second time will result in an assertion failure, because the unique_ptr has already been moved/lost during the first call.
One also need to know, that lambdas capturing unique_ptr cannot be converted into std::function because std::function requires that the callable object is copyable.
auto lambdaWithoutCapture = [](){return 1;}; //Can be std::function
auto lambdaWithCapture = [=](){return 1;}; //Can be std::function
auto lambdaWithCapture2 = [&](){return 1;}; //Can be std::function
auto lambdaWithCapture3 = [uptrProblematic = std::move(uptrProblematic)]() mutable {return 1;}; //Can't be std::function
Therefore, if you don't have to specify return type of the function, you can use such approach which does not use std::function. But you need to know, that this will only work in local scope. You can't declare auto workerFactory(); in header file, as this will raise compilation error.
auto workerFactory()
{
std::unique_ptr uptrProblematic = std::make_unique<int>(9);
int importantData = 71;
return [=, uptrProblematic = std::move(uptrProblematic)](std::string input) mutable -> int {
std::cout << "Problematic variable is equal to: " << *uptrProblematic << "\n";
std::cout << "Important data is equal to: " << importantData << "\n";
std::cout << "Input equal to: " << input << "\n";
return 9;
};
}
int main()
{
auto worker = workerFactory();
worker("Test");
}