I'm seeing code that looks like this:
template<class Function>
void MyFunc(Function&& function) { function(...); }
What's the advantage of && here, as opposed to just copying the function by value? For reference, I'm using C++14.
The problem comes from avoiding copies.
Imagine this:
auto lambda = [ptr = std::make_unique<int>(0)]() mutable {
std::cout << *ptr;
ptr = std::make_unique<int>(*ptr + 1); // why not?
};
MyFunc(lambda); // use it normally
MyFunc([]{ std::cout << " end"; }); // use by using a temporary lambda
lambda() // just call the function after that
If the signature is MyFunc(Function f), it would require a std::move and the lambda would not be useable after the call.
If the signature is MyFunc(Function const& f), it would not work since the lambda is mutable.
If it was MyFunc(Function& f) then the temporary would not work.
You're basically left with MyFunc(Function&& f).
The real question however is "Do I need to support all these cases?"
I would tell: most of the time no. Most of the time, receiving the lambda by value is the simplest and support almost every cases. This is the way the STL went.
Why? Because perfect forwarding of function objects is really hard to get perfect, and you cannot call the function multiple times in most of the cases in a pefectly generic way. I would perfect forward a function only if I want to wrap it, want to completely avoid copies and I expect function objects that are ref qualified to temporaries.
Related
I have a piece of code which calls an async rdma-write. The rdma API receives a void* context which I would like to use to pass a callback to be called when the operation finishes.
void invoke_async_operation(... some stuff to capture ...) {
...
MyCallBackType* my_callback = // Create callback somehow
rdma_post_write(..., my_callback);
...
}
void on_complete(void* context) {
(*(MyCallbackType*)context)();
}
I thought using a lambda here would be best, because it will easily capture all the context which is required to the later callback invokement. However I saw in What is the lifetime of a C++ lambda expression? that a lambda lifetime is limited to the scope where it was defined.
Note that I can't copy the lambda, because context is a pointer.
What is the correct approach here? Should I insist on using lambdas and prolong their lifetime somehow, or is there a better way? Thanks.
Lifetime of a lambda
The object that represents the lamda expression and allows to invoke it, obeys indeed the usual scoping rules.
However this object can be copied (e.g passing it as argument to a function or a constructor, or assigning it to a global, or whatever else you want to do) so that the lambda can be invoked at any later point, even after the scope it was initially defined in is left.
Because of exactly this potentially long survival of lambdas, you can find quite a few questions, blogs or books that will advise on careful use of the lambda capture, especially if captured by reference, because the lambda itself (and not its anonymous proxy object) can be called even after the referred objects are destroyed.
Your callback issue
You are constraint in your design by the use of an OS callback that can only convey a raw pointer that was passed to it when the callback was set up.
The way to approach this could be to use a std::function object of the standard <functional> library. Here a small function to show you how it works:
function<void()>* preparatory_work() {
auto l = [](){ cout<< "My lambda is fine !" <<endl; } ; // lambda
function<void ()> f = l; // functor
auto p = new function<void()>(l); // a functor on the heap
l(); // inovke the lambda object
f(); // invoke the functor
(*p)(); // invoike functor via a pointer
return p;
}
Function objects are as handy to use as any other object and as easy to declare as function pointers. They are however much more powerful than function pointers, because they can refer basically to any callable object.
As you see, in the example above, I allocated a function objet with new, and returned its pointer. So you could indeed later invoke this function:
int main() {
auto fcp = preparatory_work(); // fcp is a pointer
(*fcp)();
// and even with casting as you would like
void *x = (void*)fcp;
(*(function<void()>*)x)(); // YES !!!
}
Here an online demo
I'm trying to std::bind a std::move on a std::unique_ptr. The resulting function object seems to be immutable, so it would be impossible to perform the move when the functor is invoked.
I suspect this is because of the same reason why lambdas are immutable by default - invoking them should do the same thing every time. However there are cases where they need to be mutable, which is why we have the mutable keyword.
void foo(std::unique_ptr<int>&& ptr)
{
cout << *ptr << endl;
}
int main()
{
std::unique_ptr<int> ptr = std::make_unique<int>(123);
std::bind(foo, std::move(ptr))(); // Doesn't compile
[&ptr]() { foo(std::move(ptr)); }(); // Equivalent, doesn't compile
[&ptr]() mutable { foo(std::move(ptr)); }(); // Compiles
return 0;
}
Instad of using bind I could wrap a function call in a mutable lambda. However at least to me personally bind looks much cleaner and simpler in this case.
I understand that invoking the mutable lambda twice would lead to undefined behavior, because I would be moving again from an already moved-from pointer. But in my case I know the functor will only be called once.
Is there a way I could use std::bind to do this? Is there a bind_mutable of sorts? If not, how should I go about writing it myself?
However at least to me personally bind looks much cleaner and simpler in this case.
Do not use std::bind in C++11. Use lambdas instead. std::bind has several issues excellently explained in this talk by Stephan T. Lavavej “functional: What's New, And Proper Usage".
It might look simpler and cleaner in this case, but it's not recommended.
Writing...
[&ptr]{ foo(std::move(ptr)); }();
...is the proper way of solving this problem.
I'm trying to make a function that accepts a shared pointer to some functor. With manually crafted functors there're no problems, but with lambda there are. I know that I can't use decltype with lambda - every new lambda declaration creates a new type. Right now I'm writing:
auto lambda = [](int a, float b)->int
{
return 42;
};
using LambdaType = decltype(lambda);
shared_ptr<LambdaType> ptr{ new LambdaType{ lambda } };
It works, but looks ugly. Moreover there's a copy constructor call! Is there any way to simplify?
You could use std::function as type.
Lambdas are merely auto written invokable objects to make simple code simple. It you want something beyond their default automatic storage behavior, write the type they write yourself.
It is illegal to have a lambda type in an unevaluated context. In an evaluated context, it creates a lambda in automatic storage. You want it on the free store. This requires at least logically a copy.
A horrible hack involving violating the unevaluated context rule, sizeof/alignof, aligned_storage_t, placement new, possibly unbounded compile time recursion (or maybe one with a static_assert), returning pointers to local variables, and the aliasing constructor of shared ptr, and requiring callers to write insane code might avoid calling the copy/move. But it is a bad idea, and simply using invokable objects is easier.
Of course, accepting the copy/move makes it trivial. But at that point, just use std::function unless you need something like varargs.
You state you do not want to force users to use std::function; but std::function would implicitly convert a compatible lambda into itself.
If you are willing to accept a copy, we can do this:
template<class T>
std::shared_ptr<std::decay_t<T>>
auto_shared( T&& t ) {
return std::make_shared<std::decay_t<T>>(std::forward<T>(t));
}
then auto ptr = auto_shared( [x=0]()mutable{ return x++; } ); is a non-type-erased shared pointer to a counting lambda. The lambda is copied (well, moved) into the shared storage.
If you want to avoid that copy, the client can write a manual function object and call make_shared<X>(ctor_args) on it.
There is no reasonable way to separate a lambdas type from its construction in C++ at this point.
if you catch something in lambda, it becomes algorithmically same as std::function, so use it freely. Also, std::function implements captured values memory management, so using std::shared_ptr on top of it is not required.
If you catch nothing, lambda is convertible to simple function pointer:
int(*ptr)(int,int) = [](int a, int b) -> int {
return a+b;
};
Functions are allocated statically and definitely shouldn't be deleted. So, you don't actually need std::shared_ptr
Imagine the following scenario:
typedef std::function<float(float)> A;
typedef float(*B)(float);
A foo();
void bar(B b);
You wish to do something along the lines of:
bar(foo());
Obviously this does not work. Mainly because A can contain a state and B is a function pointer. What if we know that A does not contain a state and we wish to somehow take it's "meaning" and put it into something that can be passed for a B?
Is it impossible?
If you can ensure that the callable object stored in A is a function pointer or a lambda with an empty capture list, you can simply get a function pointer in this way:
foo().target<B>();
In general, a std::function can "box" some closure (e.g. the value of some lambda function). And a closure contains both code and data (the closed values). So I believe that you cannot portably convert it to a naked function pointer. BTW, because conceptually closures are mixing code and data languages not providing them (like C) practically requires callbacks (i.e. the convention to pass every function pointer with some additional data, look into GTK for a concrete example).
Some implementation specific tricks might make a trampoline function on the stack (e.g. dynamically generate, perhaps with asmjit, some machine code containing a pointer to the closure, etc.). But this is not portable and system specific (in particular because the stack needs to be executable)
What if we know that A does not contain a state and we wish to somehow take it's "meaning" and put it into something that can be passed for a B?
Even that isn't sufficient. std::function provides a target() member function, that if you know the exact type of the underlying functor, you can get it back. So we can do, for instance:
void print(int i) { std::cout << i; }
std::function<void(int)> f = print;
auto ptr = f.target<void(*)(int)>(); // not null
(*ptr)(42); // works
However, even if our functor f doesn't contain state, that doesn't mean that its underlying type is precisely void(*)(int). It could be a completely different function pointer, in which case we wouldn't be able to pull it out:
int square(int i) { return i*i; }
f = square;
ptr = f.target<void(*)(int)>(); // nullptr!
Or it could be a lambda, in which case we wouldn't even be able to name the type, much less pull it out:
f = [](int i){ std::cout << i; }; // same as print, right?
ptr = f.target<void(*)(int)>(); // ... nope :'(
Basically, type erasure is really type erasure. If you need the original underlying type, that's likely indicative of a bad design.
There are two ways to use lambda function variable:
std::function<int(int, int)> x1 = [=](int a, int b) -> int{return a + b;};
//usage
void set(std::function<int(int, int)> x);
std::function<int(int, int)> get();
And:
std::function<int(int, int)>* x2 = new std::function<int(int, int)>([=](int a, int b) -> int{return a + b;});
//usage
void set(std::function<int(int, int)>* x);
std::function<int(int, int)>* get();
I would like to know what are the differences, because I do not know how the lambda function data is stored.
I would like to know the best way in terms of peformance, memory usage and the best way to pass a lambda function as argument or return lambda function.
I would prefer to use pointers if the size of the lambda function object is bigger than 4 or to avoid errors (if some kind of copy constructor is executed when I do an attribution or if some kind of destructor is executed when I do not want).
How should I declare lambda function variables?
EDIT
I want to avoid copies and moves, I want to continue to use the same function again.
How should I change this example?
int call1(std::function<int(int, int)> f){
return f(1, 2);
}
int call2(std::function<int(int, int)> f){
return f(4, 3);
}
std::function<int(int, int)>& recv(int s){
return [=](int a, int b) -> int{return a*b + s;};
}
int main(){
std::function<int(int, int)> f1, f2;
f1 = [=](int a, int b) -> int{return a + b;};
f2 = recv(10);
call1(f1);
call2(f1);
call1(f2);
call2(f2);
}
I cannot return reference in the function recv:
warning: returning reference to temporary
Is this a good solution?
int call1(std::function<int(int, int)>* f){
return (*f)(1, 2);
}
int call2(std::function<int(int, int)>* f){
return (*f)(4, 3);
}
std::function<int(int, int)>* recv(int s){
return new std::function<int(int, int)>([=](int a, int b) -> int{return a*b + s;});
}
int main(){
std::function<int(int, int)> f1 = [=](int a, int b) -> int{return a + b;};
std::function<int(int, int)> *f2 = recv(10);
call1(&f1);
call2(&f1);
call1(f2);
call2(f2);
delete f2;
}
EDIT (Conclusion)
A lambda function object is like any object that is instance of a class. The rules for allocation, arguments and attribution are the same.
It doesn't make sense to create pointer of std::function. It just doesn't benefit you in any way. Instead of benefits, it puts more burden on you, as you've to delete the memory.
So the first version (i.e the non-pointer version) is all that you should go for.
In general, like a rule of thumb, avoid new as much as possible.
Also, you don't need std::function everytime you use lambda. Many times, you could just use auto as:
auto add = [](int a, int b) { return a + b;};
std::cout << add(100,100) << std::endl;
std::cout << add(120,140) << std::endl;
You've made it clear that you want to use pointers. So... do that.
But at least use a smart pointer. Proper use of std::shared_ptr would prevent a number of problems. Of course, you have to make sure to avoid circular references, but for lambdas, that seems unlikely.
Granted, it's still a terrible idea. But it's only terrible in the sense of being a completely pointless premature optimization done to make yourself feel better about passing things around, rather than having any actual measurable benefit in your code's actual running time. At least with a shared_ptr, you're less likely to accidentally delete the memory or run into exception safety issues.
I'm going to ignore the bad C++ practice of heap-allocating something you could just as easily stack allocate, as well as the pain of tracking this memory without the use of a smart pointer. This will assume that you know what you're doing and will instead focus on the "performance" and "memory usage" issues you asked about.
Do not take this as an endorsement of what you're wanting to do.
std::function will generally be implemented by doing an internal heap allocation of some object; that's necessary due to the type-erasure. So it will be at least one pointer in size; possibly more. The size of the heap allocation will likely be a vtable pointer + the size of your lambda class. And the size of that is governed by how much stuff you capture and whether it is by value or reference.
Like most C++ standard library objects, std::function is copyable. Performing a copy will actually copy it, not do a pretend copy where you now have two objects with the same pointer. So each one will have an independent copy of the internal heap object. That is, copying it will mean doing another heap allocation. This will also copy the lambda itself, which means copying everything that's captured within it.
However, like most C++ standard library objects, std::function is movable. This does not do any memory allocation whatsoever.
Therefore, if you want to do this, it's pretty cheap:
std::function<int(int, int)> x1 = [=](int a, int b) -> int{return a + b;};
//usage
void set(std::function<int(int, int)> x);
const std::function<int(int, int)> &get();
set(std::move(x1)); //x1 is now *empty*; you can't use it anymore.
Your set function can move it into its own internal storage as needed. Note that get now returns a const&; this is contingent on the storage for these functions not going anywhere.
How cheap will move be? It will probably be the equivalent of copying just the fields of std::function, as well as blanking or otherwise neutralizing the original one. Unless you're in performance-critical code, this will not be anything you should ever be concerned about.
Here are the guidelines I tend to follow with the "functional C++" these new lambda expressions (plus std::function & std::bind) give you. Feel free to ignore them or adopt them as you see fit:
1) Assign any lambda you want to have a name as a std::function. If you're passing it into some function "X(..)" and never looking at it again, declare it in the function call so that "X" can take advantage of the fact that it is a temporary.
// I want a real name for this (plan to use multiple times, etc.)
// Rarely are you going to do this without moving the lambda around, so
// declaring it as 'auto' is pointless because C++ APIs expect a real type.
std::function<double(double)> computeAbs = [](double d) -> double { return fabs(d); };
// Here, we only ever use the lambda for the call to "X".
// So, just declare it inline. That will enforce our intended usage and probably
// produce more efficient code too.
X([](double r) -> double { return fabs(r); });
2) If you plan to move functions all over the place, use some sort of reference-counted wrapper around std::function. The idea is to pass around a safe pointer to the actual std::function, thus avoiding costly copies as well as worrying about new and delete.
Building your own class for doing this can be a pain, but it will ensure you only take the hit for actually converting your lambda, function ptr, etc. into a std::function once.
You can then provide an API like "GetFunction" to return the std::function you carry by value for APIs that expect them.
3) For public APIs taking std::function or lambdas, just pass by value.
Yes, you CAN get passing by reference or even r-value (those '&&') references to work and they're even the right solution in some situations. But lambdas are nasty in that their actual type is literally unknowable to you. However, they are all convertible to std::function in the same way that all primitive types can convert to 'int', so passing them into functions involves using the same tricks that let you pass chars and floats into a function like "f(int a)".
Namely, you create functions "f" that are either templated on the TYPE of the functor argument like:
template<typename Functor>
double f(Functor absFunc);
OR, you make everybody normalize to std::function:
double f(std::function<double(double)> absFunc);
Now, when you call "f([](double r) -> double { return fabs(r); })" the compiler knows to how to handle it. Users get something that 'just works' without having to code around your API, which is what you want.