return lambda by rvalue ref? - c++

#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;
}

Related

Is it safe to pass std::function<bool(std::string)> &&callback (i.e. as a rvalue move) and what is the effect?

Given the following working code (main.cpp):
#include <functional>
#include <iostream>
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback) // <--- this line
{
m_callback = std::bind(callback, std::placeholders::_1);
callback("hello world!\n");
}
};
// pretty boring class - a cut down of my actual class
struct helper
{
worker the_worker;
bool work_callback(std::string str)
{
std::cout << str << std::endl;
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });
}
Compiled with: -std=c++11 -O2 -Wall -Wextra -pedantic-errors -O2 main.cpp
I have comment the line in question (<-- this line - around line 7), where I think it would be more efficient to use: void do_work(std::function<bool(std::string)>&& callback) i.e. using the && move semantic.
I have never really used this, mostly because I still don't quite understand it.
My understanding is this:
void do_work(std::function<bool(std::string)> callback) - will take a copy of the lambda that I pass in (which is an rvalue I think).
void do_work(std::function<bool(std::string)> callback) - will move the lambda that I pass in because it is an rvalue.
My crude idea of an rvalue is any temporary variable.
Questions:
What I am not 100% clear about is, is what I wrote correct? and therefore is it safe to use &&. Both seem to work.
Does this && method also work if instead of passing a lambda like this:
the_helper.the_worker.do_work( [&](std::string data){ return the_helper.work_callback(data); });
we pass in std::bind(...):
the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1));
If the parameter is defined as an rvalue-reference, you must pass a temporary or cast an lvalue to an rvalue, like with std::move().
And the semantics of rvalue-references are that the caller should expect the passed argument to be plundered, rendering it valid but arbitrary, meaning mostly useless.
But the function receiving an rvalue-reference, despite having license to plunder, does not have any obligation to plunder. And if it doesn't explicitly do so, for example by passing that license on, then it doesn't come to pass, and nothing special happens.
Your code is such a case.
While I would ban std::bind from my vocabulary, using it or not doesn't actually make any significant difference.
In this case regardless of whether you pass by value or by rval ref a temporary std::function will have to be created, that's because a lambda is not really a std::function. In any case, you should move the std::function before assigning, to avoid making an unnecessary copy.
I'd recommend passing by value in this case, as this is a bit more flexible, and if you are passing lambdas, then it does not cause any harm, as the std::function will usually be constructed in place (so the temporary will not be moved into the function; this move can, and usually will, be elided).

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 &&

std::bind binds "by value", is that true?

I just wonder whether the following class will work properly. What I'm a bit scared of is the fact that in the constructor, on the marked line, I bind to values which are just (temporary) arguments. So the question is: Does std::bind take the arguments by-value? To me, this is not clear in the documentations I read.
class BoundFct {
public:
BoundFct(function<void(int, int)> fct, int v){
boundFct = bind(fct, v, _1); // ** PROBLEM HERE ? **
}
void call(int i){
boundFct(i);
}
private:
function<void(int)> boundFct;
};
As far as I tested, it works as intended. But is it a safe approach that will work properly in any case?
From std::bind:
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
There's nothing unsafe about your code. Though it'd be better to take any function in your BoundFct constructor, rather than a std::function<>.

Using C++11 lambdas asynchronously, safely

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.

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");
}