I have an class job. I want to create a unique_ptr of job, capture it in a lamdba and execute a function in a lambda which forwards this pointer:
The function:
void printJob(std::unique_ptr<job> aJob)
Lamdba:
auto jobptr = std::make_unique<job>(<arguments>);
auto function = [this, j = std::move(jobptr)]
{
printJob(j);
};
The function is executed on a different thread therefor the lamdba is used
The j argument in the lamdba is of type std::remove_reference_t<std::unique_ptr<job> &> while the function need a std::unique_ptr<job>. Can I make this work? Tried options with std::move and std::forward but I cant get it to compile. I am using C++14.
I have found alternatives (shared_ptr, raw pointer, etc) but this is more in sync with the existing code.
If printJob's parameter is a std::unique_ptr<job> then it must be passed in via move semantics, via std::move itself.
Captured objects in regular lambdas are, effectively, const object, hence they are not movable. The solution is simple: use a mutable lambda.
auto function = [this, j = std::move(jobptr)]
mutable {
printJob(std::move(j));
};
It goes without saying that this lambda can only be effectively executed just once.
But does printJob really need to take ownership of the passed in parameter? If not, if it's just as happy as
void printJob(const std::unique_ptr<job> &aJob)
then none of this is needed.
Related
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.
Can I pass a unique_ptr's reference to a function? If not why should I avoid it?
Ex:
void func(unique_ptr<Clss>& ref);
main() {
unique_ptr<Clss> a = std::make_unique<Clss>();
fn(a);
}
Can I pass a unique_ptr's reference to a function?
Yes, a unique_ptr is class like any other.
You should do this when you want to mutate an existing unique_ptr from a function (e.g. calling .reset() on it).
If only you want to access the object inside unique_ptr<T>, take T& or const T& in your function interfaces, so that they can be used independently of unique_ptr.
According to Herb Sutter:
https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
Passing unique_ptr by reference is for in/out unique_ptr parameters.
void f( unique_ptr<widget>& ); // (d)
This should only be used to accept an in/out unique_ptr, when the function is supposed to actually accept an existing unique_ptr and potentially modify it to refer to a different object. It is a bad way to just accept a widget, because it is restricted to a particular lifetime strategy in the caller.
Thanks #sgvd
See this code snippet, two ways of passing unique_ptr as function parameter. fun1 will take ownership of the object ( hence should be forwarded from the caller) but func2 commits thats the reference unique_ptr object will be passed as reference and will not be modified by the function.
void func1(unique_ptr<Clss>&& moved_obj) // this function takes ownership
{
//do something with the moved_obj
moved_obj.reset();
}
void func2(const unique_ptr<Clss>& ref_obj) // this function takes reference
{
unique_ptr<Clss> new_obj = std::make_unique<Clss>(*(ref_obj));
}
int main() {
unique_ptr<Clss> a = std::make_unique<Clss>();
func1(std::move(a));
unique_ptr<Clss> b = std::make_unique<Clss>();
func2(b);
return 0;
}
I see those valid meaningful signatures:
void take_ownership(std::unique_ptr<Clss>);
// or void take_ownership(std::unique_ptr<Clss>&&);
void use(/*const*/ Clss*);
// or void use(/*const*/ Clss&);
std::unique_ptr<Clss> create(/*args..*/);
void might_take_ownership(std::unique_ptr<Clss>&);
The later might make sense, but it is more difficult to reason with (as any I/O argument).
If you can, prefer one of the other.
Passing a std::unique_ptr to a function is perfectly fine as long as you respect the same rules you would when passing a regular reference to a function:
the underlying std::unique_ptr and the object it points to must live at least as long as the function will use the reference;
in case of multi-threading, barriers must be put in place.
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 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
Let's say I have a function which takes an std::function:
void callFunction(std::function<void()> x)
{
x();
}
Should I pass x by const-reference instead?:
void callFunction(const std::function<void()>& x)
{
x();
}
Does the answer to this question change depending on what the function does with it? For example if it is a class member function or constructor which stores or initializes the std::function into a member variable.
If you want performance, pass by value if you are storing it.
Suppose you have a function called "run this in the UI thread".
std::future<void> run_in_ui_thread( std::function<void()> )
which runs some code in the "ui" thread, then signals the future when done. (Useful in UI frameworks where the UI thread is where you are supposed to mess with UI elements)
We have two signatures we are considering:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Now, we are likely to use these as follows:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
which will create an anonymous closure (a lambda), construct a std::function out of it, pass it to the run_in_ui_thread function, then wait for it to finish running in the main thread.
In case (A), the std::function is directly constructed from our lambda, which is then used within the run_in_ui_thread. The lambda is moved into the std::function, so any movable state is efficiently carried into it.
In the second case, a temporary std::function is created, the lambda is moved into it, then that temporary std::function is used by reference within the run_in_ui_thread.
So far, so good -- the two of them perform identically. Except the run_in_ui_thread is going to make a copy of its function argument to send to the ui thread to execute! (it will return before it is done with it, so it cannot just use a reference to it). For case (A), we simply move the std::function into its long-term storage. In case (B), we are forced to copy the std::function.
That store makes passing by value more optimal. If there is any possibility you are storing a copy of the std::function, pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function and having one sub method after another use it. Barring that, a move will be as efficient as a const&.
Now, there are some other differences between the two that mostly kick in if we have persistent state within the std::function.
Assume that the std::function stores some object with a operator() const, but it also has some mutable data members which it modifies (how rude!).
In the std::function<> const& case, the mutable data members modified will propagate out of the function call. In the std::function<> case, they won't.
This is a relatively strange corner case.
You want to treat std::function like you would any other possibly heavy-weight, cheaply movable type. Moving is cheap, copying can be expensive.
If you're worried about performance, and you aren't defining a virtual member function, then you most likely should not be using std::function at all.
Making the functor type a template parameter permits greater optimization than std::function, including inlining the functor logic. The effect of these optimizations is likely to greatly outweigh the copy-vs-indirection concerns about how to pass std::function.
Faster:
template<typename Functor>
void callFunction(Functor&& x)
{
x();
}
As usual in C++11, passing by value/reference/const-reference depends on what you do with your argument. std::function is no different.
Passing by value allows you to move the argument into a variable (typically a member variable of a class):
struct Foo {
Foo(Object o) : m_o(std::move(o)) {}
Object m_o;
};
When you know your function will move its argument, this is the best solution, this way your users can control how they call your function:
Foo f1{Object()}; // move the temporary, followed by a move in the constructor
Foo f2{some_object}; // copy the object, followed by a move in the constructor
Foo f3{std::move(some_object)}; // move the object, followed by a move in the constructor
I believe you already know the semantics of (non)const-references so I won't belabor the point. If you need me to add more explanations about this, just ask and I'll update.