Moving with lambdas - c++

When using lambda functions, let's say that you decide to copy a variable (with the [=] notation). If you never reference that variable again, is the compiler allowed to move it into the resultant function object?
Edit: For example, I've wrote a snippet to move calls across threads. Here's a sample that does so.
extern "C" __declspec(dllexport) void parser_file_updated(Parser* p, const char* filename, int offset, int added) {
std::string file(filename);
p->make_call([=]() {
p->file_updated(std::move(file), offset, added);
});
}
But clearly, the file variable doesn't need to live past the lambda definition- and indeed, the lambda is only called once, so I moved the copy.

If you never reference that variable again, is the compiler allowed to move it into the resultant function object?
No. The only situation where the compiler is allowed to replace a copy with a move are the exact same situations where it is allowed to perform a copy elision. These situations include returning a local object by value or initializing an object with a temporary. In these cases the compiler is allowed to elide the copy by making source and target the same object. If the compiler is not able to do that for whatever reason it has to consider the source object as an rvalue with respect to overload resolution for selecting the appropriate constructor for the target object. In your case, however, file is an Lvalue and none of the cases from above apply. You would have to use an explicit move.
Unfortunately, C++11 doesn't have a syntax for a "move capture". IMHO, it's a shame. But std::bind supports this. It should be possible to combine std::bind with a lambda expression like this:
void foo(char const* p) {
string s = p;
auto fun = bind([](string const& s){
...
},move(s));
fun();
}
so that the string is moved into the function object.
If you intent to call this function only once and want to move the string out of the function object again, you can use a non-const reference:
void foo(char const* p) {
string s = p;
auto fun = bind([](string & s) {
some_other_func(move(s));
},move(s));
fun();
}
Note that, if you don't want to use bind here but let the lambda object's constructor create a copy of s, moving the string out of the function object requires the mutable keyword:
void foo(char const* p) {
string s = p;
auto fun = [=]() mutable {
// ^^^^^^^
some_other_func(move(s));
};
fun();
}
because otherwise the closure type's operator() function will be const-qualified which in turn makes s a const-qualified string.
In C++14 the lambda capture clause got a little more flexible. We can now write
void foo(char const* p) {
string s = p;
auto fun = [s=move(s)]() mutable { // #1
some_other_func(move(s)); // #2
};
fun();
}
where #1 moves the string value into the lambda object and #2 moves the string value out (depending on how some_other_func is declared exactly).

Update C++14: It is possible with initialised captures (added with this version):
[x = std::move(y)]() { /* ... */ }
Though with variadic templates I only managed to get the appropriate effect via a std::tuple and std::apply (if I missed some syntactic sugar for appreciate a hint...):
template <typename ... T>
void f(T&& ... t)
{
[x = std::tuple<T...>(std::move(t) ...)]()
{
std::apply([&](auto const& ... t) { /* ... */ }, x);
}
}
Demonstration on godbolt – note how the strings get emptied illustrating how their contents are moved into x or into the tuple.

Related

What is the difference between lambda capture [&args...] and [...args = std::forward<Args>(args)]

I'm writing a simple game with Entity Component System. One of my components is NativeScriptComponent. It contains the instance of my script. The idea is that I can create my NativeScriptComponent anytime and then Bind to it any class implementing Scriptable interface. After that my game's OnUpdate function will automatically instantiate all scripts in my game and will call their OnUpdate function.
My scripts can have their own, different constructors so I need to forward all the arguments to them when I bind my script.
Consider the following code:
#include <iostream>
#include <memory>
#include <functional>
using namespace std;
struct Scriptable
{
virtual void OnUpdate() {};
};
struct MyScript : Scriptable
{
MyScript(int n) : value(n) {}
void OnUpdate() override {cout << value;}
int value;
};
struct NativeScriptComponent
{
unique_ptr<Scriptable> Instance;
function<unique_ptr<Scriptable>()> Instantiate;
template<typename T, typename ... Args>
void Bind(Args&&... args)
{
// (A)
Instantiate = [&args...]() { return make_unique<T>(forward<Args>(args)...); };
// (B) since C++20
Instantiate = [...args = forward<Args>(args)]() { return make_unique<T>(args...); };
}
};
int main()
{
NativeScriptComponent nsc;
nsc.Bind<MyScript>(5);
// [..] Later in my game's OnUpdate function:
if (!nsc.Instance)
nsc.Instance = nsc.Instantiate();
nsc.Instance->OnUpdate(); // prints: 5
return 0;
}
1) What is the difference between option A and B
Instantiate = [&args...]() { return make_unique<T>(forward<Args>(args)...); };
vs
Instantiate = [...args = forward<Args>(args)]() { return make_unique<T>(args...); };
Why can't I use forward<Args>(args) inside make_unique in option B?
Are both A and B perfectly-forwarded?
For added completeness, there's more things you can do. As pointed out in the other answer:
[&args...]() { return make_unique<T>(forward<Args>(args)...); };
This captures all the arguments by reference, which could lead to dangling. But those references are properly forwarded in the body.
[...args=forward<Args>(args)]() { return make_unique<T>(args...); };
This forwards all the arguments into the lambda, args internally is a pack of values, not references. This passes them all as lvalues into make_unique.
[...args=forward<Args>(args)]() mutable { return make_unique<T>(move(args)...); };
Given that, as above, args is a pack of values and we're creating a unique_ptr anyway, we probably should std::move them into make_unique. Note that the lambda has its own internal args here, so moving them does not affect any of the lvalues that were passed into this function.
[args=tuple<Args...>(forward<Args>(args)...)]() mutable {
return std::apply([](Args&&... args){
return std::make_unique<T>(forward<Args>(args)...);
}, std::move(args));
};
The most fun option. Before we'd either capture all the arguments by reference, or forward all the args (copying the lvalues and moving the rvalues). But there's a third option: we could capture the lvalues by reference and move the rvalues. We can do that by explicitly capturing a tuple and forwarding into it (note that for lvalues, the template parameter is T& and for rvalues it's T - so we get rvalues by value).
Once we have the tuple, we apply on it internally - which gives us Args&&... back (note the && and that this is not a generic lambda, doesn't need to be).
This is an improvement over the previous version in that we don't need to copy lvalues -- or perhaps it's worse because now we have more opportunity for dangling.
A comparison of the four solutions:
option
can dangle?
lvalue
rvalue
&args...
both lvalues and rvalues
1 copy
1 move
...args=FWD(args) and args...
no
2 copies
1 move, 1 copy
...args=FWD(args) and move(args)...
no
1 copy, 1 move
2 moves
args=tuple<Args...>
lvalues
1 copy
2 moves
A captures the arguments by reference and then perfectly forwards into make_unique. Unfortunately by that point the references are (probably) dangling, so calling Instantiate in your example has undefined behaviour.
B perfectly forwards the arguments into the data members of the closure object, then copies those data members into make_unique. You can't forward here without marking the lambda mutable, because the body of a lambda is a const member function of the closure object.
A can't forward rvalues, the references to them dangle. B can't forward lvalues, it does a copy.
If you only want to instantiate one Scriptable, then you can mark the lambda in B as mutable, and move in there. If you want to construct multiple Scriptables, you will have to do some copying.

Spamming std::move is the way to go?

About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-
If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
Responsibility of std::move is calling operator=(A&& other).
The most essential step of the move operation is supposed to be implemented in operator=(A&&).
It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.
Question
After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).
Do I really have to use std::move to transfer ownership?
Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?
Should std::move be encapsulated?
They are actually a single question, but ask in different perspectives.
Edit
As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern.
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
Rule of thumb:
If you're in a deduced x-value context, use std::forward:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
Otherwise use std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
It is permissible, if not necessarily advisable to write code like this:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const r-value references do exist, it's just that no-one uses them because there is no reasonable use-case.
The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.
To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.
In fact, std::move is little more than a cast to an rvalue reference.
There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:
std::unique_ptr<int> a;
a = new int;
But the following does, without needing a move:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.
Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.

Is there any real use case for function's reference qualifiers?

Recently I learned about function's reference qualifiers, e.g.
struct foo
{
void bar() {}
void bar1() & {}
void bar2() && {}
};
Where I might need this feature, is there any real use case for this language feature ?
Where I might need this feature, is there any real use case for this language feature ?
The example you show is pretty useless, it's more useful when you have an overloaded function, one version that operates on lvalues and one that operates on rvalues.
Consider a type a bit like std::stringstream that owns a string and returns it by value. If the object is an rvalue, it can move the string instead of copying it.
class StringBuilder
{
public:
std::string get() const& { return m_str; }
std::string get() && { return std::move(m_str); }
private:
std::string m_str;
};
This means when you return a StringBuilder from a function and want to get the string out of it, you don't need a copy:
std::string s = buildString().get();
More generally, given a function f(const X&) if it would be useful to overload it with f(X&&), then given a member function X::f() it might be useful to change it to X::f() const& and overload it with X::f()&&
There are basically two uses:
To provide an optimized overload, for example to move a member out of a temporary object instead of having to copy it.
Prevent misuse of an API. For example, no one would expect
int a = 1 += 2;
to work and this would also cause a compile error. However
string b = string("foo") += "bar";
is legal if operator += is declared as
string & operator += (string const & o);
as is usually the case. Also this has the nasty side-effect of providing an lvalue-reference to your rvalue. Bad idea. This can easily be prevented by declaring the operator as
string & operator += (string const & o) &;

Is there a way to make passing by reference, and passing by value explicit in the function call?

If you were to look at this code,
int x = 0;
function(x);
std::cout << x << '\n';
you would not be able to verify through any means of syntax, that parameter x is being passed by reference or that it's being passed by value. The only way you would know for sure, is if you looked at either the function declaration or function definition.
Here is a simple example of how I believe this could be a problem:
std::string Lowercase(std::string str); //<- this is hidden away in code; probably in a different file.
int main(){
std::string str = "HELLO";
Lowercase(str);
std::cout << str << '\n'; //<- Bug! we expected to output "hello". The problem is not very easy to spot, especially when a function name sounds as though it will change the passed in value.
}
In order to avoid having to jump between the function call and the function declaration (or in some cases, the documentation) in order to understand the function behavior, is there a way to explicitly document in the syntax of a function call that the parameter is expected to change (i.e. a reference parameter) or that a copy is being sent (i.e. pass by value)?
I realize that there is also the option of passing by const& which has the similar notion to passing by value, in that the variable passed in, will not have its value changed after the function call.
I'm sure there are all kinds of situations in the language that might add to the complexity of understanding how a parameter is being passed-
but I'm curious, is there a way to combat this problem in the way I want to?
I've noticed that some people write two similar functions. One of them takes a value parameter, the other one takes a pointer. That allows calling a function like this:
Lowercase(str); //we assume the value will not change
Lowercase(&str); //we assume the value will change
But this solution has many other issues, and I would not like to lose the benefit of references. Plus, we are still making assumptions on the behavior.
Some people insist that the correct way to pass mutable object is to use a pointer. That is, you would pass
Lowercase(&str);
... and Lowercase() would, obviously, be implemented to take a pointer. That approach may suit your needs.
I want to mention, however, that this is not what I would do! Instead, the approach I favor is to use appropriate names instead. For example,
inplace_lowercase(str);
pretty much says what it is going to do. Clearly, inplace_lowercase() would actually be an algorithm and with a bit of magic could be reasonably be called as
inplace_lowercase(str.begin() + 1, str.end());
as well.
Here are a few reasons why I don't like passing arguments by pointer and/or why I don't believe in an explicit indication of how the argument is passed:
Pointers can be null. A mandated reference parameters should, in my opinion, be a reference.
Passing by pointer still doesn't indicate whether the argument may be modified are not as the argument may be a T const*.
Having meaningful names makes it actually easier to understand what's going on in the first place.
Calling something without consulting its documentation and/or knowing what the called function will do doesn't work anyway and indicating how things are passed is trying to cure symptoms of a deeper problem.
I'm not sure I understand your requirements completely, but maybe this is something you can use:
template<typename T>
void foo( T ) { static_assert( sizeof(T)==0, "foo() requires a std::ref" ); }
void foo( std::reference_wrapper<int> t )
{
// modify i here via t.get() or other means of std::reference_wrapper
}
int main()
{
int i = 42;
// foo( i ); // does not compile, static_assert fires
foo( std::ref( i ) ); // explicit std::ref visible on the caller's side
}
Many (most) IDE's help you with this problem by displaying the function/method prototype(s) once they figure out which function you are calling.
This is C++: the lack of in and out parameters doesn't mean the language is deficient, it means you need to implement what other languages would do as a language feature as a library.
Create two template classes and functions.
in_param<T> is a wrapper around a T const&, whilie io_param<T> is a wrapper around a T& reference. You construct them by calling helper functions in and io.
Inside, they behave like references (via overloading).
Outside, the caller must call in or io on the argument, marking it up at the call site.
out is trickier: inside the fumction, only assignment is legal. Ideally we would not even construct it: an emplace method might help.
However, the caller needs some channel to know if the parameter was constructed or not.
What I would do is out_param only has operator=, and it assigns. out wraps something into an out_param. If you want delayed constructuon, use optional inside the out param, which gets close. Maybe out_param also has emplace, which usually just assigns, but if the tyoe wrapped has emplace calls it instead?
template<typename T>
struct in_param : std::reference_wrapper<T const> {
explicit in_param( T const& t ):std::reference_wrapper<T const>(t) {}
in_param( in_param<T>&& o ):std::reference_wrapper<T const>(std::move(o)) {}
void operator=( in_param<T> const& o ) = delete;
};
template<typename T>
struct io_param : std::reference_wrapper<T> {
explicit io_param( T& t ):std::reference_wrapper<T>(t) {}
io_param( io_param<T>&& o ):std::reference_wrapper<T>(std::move(o)) {}
};
template<typename T>
in_param< T > in( T const& t ) { return in_param<T>(t); }
template<typename T>
io_param< T > io( T& t ) { return io_param<T>(t); }
template<typename T>
struct out_param {
private:
T& t;
public:
out_param( T& t_ ):t(t_) {}
out_param( out_param<T>&& o ):t(o.t) {}
void operator=( out_param<T> const& o ) = delete;
void operator=( out_param<T> && o ) = delete;
void operator=( out_param<T> & o ) = delete;
void operator=( out_param<T> && o ) = delete;
template<typename U>
out_param<T>& operator=( U&& u ) {
t = std::forward<U>(u);
return *this;
}
// to improve, test if `t` has an `emplace` method. If it does not,
// instead do t = T( std::forward<Us>(us)... ). (I'd use tag dispatching
// to call one of two methods)
template<typename... Us>
void emplace( Us&&... us ) {
t.emplace( std::forward<Us>(us)... );
}
};
template<typename T>
out_param<T> out( T& t ) { return out_param<T>(t); }
or something like the above.
You now get syntax like:
void do_stuff( int x, in_param<expensive> y, io_param<something> z, out_param<double> d );
int main() {
expensive a;
something b;
double d;
do_stuff( 7, in(a), io(b), out(d) );
}
and failure to call in, io or out at the call site results in compile time errors. Plus, out_param makes it quite difficult to accidentally read the state of the out variable within the function, producing some very nice documentation at the call site.
If you use MS VC++ then maybe it will be useful information about source-code annotation language (SAL)
http://msdn.microsoft.com/ru-ru/library/hh916383.aspx
I think it's something useless to notify (by language nonetheless [1]). The only needed question is : "Is my object is semantically modified ?", and so :
When you read a prototype you know if a function could modify an object (non-const ref) or not (copy or const ref).
When you use a function (even without reading [2] the prototype) if you have to be sure to not modify an object, use a const_cast.
[1] A static analyzer could do it for its purposes.
[2] If you miss, the compiler would warn you anyway.
That is the whole point of pass-by-reference -- that syntactically don't need to do anything different from passing by value.

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