Is `std::function` allowed to move its arguments? - c++

While working on this question, I noticed that GCC (v4.7)'s implementation of std::function moves its arguments when they are taken by value. The following code shows this behavior:
#include <functional>
#include <iostream>
struct CopyableMovable
{
CopyableMovable() { std::cout << "default" << '\n'; }
CopyableMovable(CopyableMovable const &) { std::cout << "copy" << '\n'; }
CopyableMovable(CopyableMovable &&) { std::cout << "move" << '\n'; }
};
void foo(CopyableMovable cm)
{ }
int main()
{
typedef std::function<void(CopyableMovable)> byValue;
byValue fooByValue = foo;
CopyableMovable cm;
fooByValue(cm);
}
// outputs: default copy move move
We see here that a copy of cm is performed (which seems reasonable since the byValue's parameter is taken by value), but then there are two moves. Since function is operating on a copy of cm, the fact that it moves its argument can be seen as an unimportant implementation detail. However, this behavior causes some trouble when using function together with bind:
#include <functional>
#include <iostream>
struct MoveTracker
{
bool hasBeenMovedFrom;
MoveTracker()
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker const &)
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker && other)
: hasBeenMovedFrom(false)
{
if (other.hasBeenMovedFrom)
{
std::cout << "already moved!" << '\n';
}
else
{
other.hasBeenMovedFrom = true;
}
}
};
void foo(MoveTracker, MoveTracker) {}
int main()
{
using namespace std::placeholders;
std::function<void(MoveTracker)> func = std::bind(foo, _1, _1);
MoveTracker obj;
func(obj); // prints "already moved!"
}
Is this behavior allowed by the standard? Is std::function allowed to move its arguments? And if so, is it normal that we can convert the wrapper returned by bind into a std::function with by-value parameters, even though this triggers unexpected behavior when dealing with multiple occurrences of placeholders?

std::function is specified to pass the supplied arguments to the wrapped function with std::forward. e.g. for std::function<void(MoveTracker)>, the function call operator is equivalent to
void operator(CopyableMovable a)
{
f(std::forward<CopyableMovable>(a));
}
Since std::forward<T> is equivalent to std::move when T is not a reference type, this accounts for one of the moves in your first example. It's possible that the second comes from having to go through the indirection layers inside std::function.
This then also accounts for the problem you are encountering with using std::bind as the wrapped function: std::bind is also specified to forward its parameters, and in this case it is being passed an rvalue reference resulting from the std::forward call inside std::function. The function call operator of your bind expression is thus forwarding an rvalue reference to each of the arguments. Unfortunately, since you've reused the placeholder, it's an rvalue reference to the same object in both cases, so for movable types whichever is constructed first will move the value, and the second parameter will get an empty shell.

Related

Is there a way for a member function to know if the object is an rvalue or lvalue?

My usecase is I have a class X which has a member function that returns a modified copy of X. Some of these member functions might be stacked like this
X X_before{init};
X X_after = X_before.op_1().op_2().op_3();
In the above code op_1 would create a copy. Now what I am thinking is that there's really no reason why op_2 and op_3 should also need to create a new copy, since X_before.op_1() is now an rvalue. Is there a way that I could achieve this in current C++? I am using C++14, but would also be interested to know if this is possible in later versions.
Since C++11 we have ref-qualified member functions, with that overload resolution could select the appropriate overloading based on the object to be called on is lvalue or rvalue.
#include <iostream>
struct S {
void f() & { std::cout << "lvalue\n"; }
void f() &&{ std::cout << "rvalue\n"; }
};
int main(){
S s;
s.f(); // prints "lvalue"
std::move(s).f(); // prints "rvalue"
S().f(); // prints "rvalue"
}

Constructor parameter access member field of object under construction

I have the following structure that has a member function pointer. My question is, is there a way for the lambda that I pass to it to refer to its own member variable? i.e.
struct Foo
{
int aVar{1};
int (*funcPtr)(int);
Foo(int (*func)(int)) : funcPtr(func) {};
};
auto bar1 = Foo([](int a) {std::cout << a;}) // ok
auto bar2 = Foo([](int a) {std::cout << a + bar2.aVar;}) // Not ok but is there a way to access the member variable of the object currently being defined?
Can I achieve something to this effect?
What I would like to achieve here is a process to automatically generate objects based on the lambda you pass in. e.g: bar2 above is an object that can return anything plus its stored value. i.e. I would like bar2.funcPtr(5) == 5 + bar2.aVar to be an invariant of the class. In the future I might need another object that can return anything minus its stored value, and I only need to pass the corresponding lambda to do that (if the lambda can access the member fields), without defining a new class or method.
The lambda must have the signature int(int) but your lambda has the signature void(int) so that's the first problem.
The other is that the lambda must capture bar2. You could use std::function for that.
#include <iostream>
#include <functional>
struct Foo {
int aVar{1};
std::function<int(int)> funcPtr;
Foo(std::function<int(int)> func) : funcPtr(func) {};
int call(int x) { return funcPtr(x); }
};
int main() {
Foo bar2([&](int a) { return a + bar2.aVar; });
std::cout << bar2.call(2); // prints 3
}
A more practical solution would be to not tie the lambda to the instance for which it was originally created but to let it take a Foo& as an argument (and not to capture it). Moving it around doesn't become such a hassle with this approach.
Example:
struct Foo {
int aVar;
int(*funcPtr)(Foo&, int); // takes a Foo& as an argument
Foo(int x, int(*func)(Foo&, int)) : aVar(x), funcPtr(func) {};
int call(int x) { return funcPtr(*this, x); }
};
int main() {
Foo bar2(10, [](Foo& f, int a) { return a + f.aVar; });
std::cout << (bar2.call(5) == bar2.aVar + 5) << '\n'; // true
Foo bar3(20, [](Foo& f, int a) { return a * f.aVar; });
std::cout << bar2.call(2) << '\n'; // 10 + 2 = 12
std::cout << bar3.call(2) << '\n'; // 20 * 2 = 40
std::swap(bar2, bar3);
std::cout << bar2.call(2) << '\n'; // swapped, now 40
std::cout << bar3.call(2) << '\n'; // swapped, now 12
}
Foo( /* ... */ )
As used in the shown code this is a constructor call. This is constructing a new object, right there.
Before the new object can be created and its constructor get invoked, the parameters to the constructor must be evaluated. This is how C++ works. There are no alternatives, or workarounds, that end up constructing the object first and only then evaluate its constructor's parameters afterwards.
For this reason it is logically impossible for a lambda, that gets passed as parameter to the constructor, "refer to its own member variable". There is nothing in existence that has "its own member variable" at this point. The object's construction has not began, and you cannot refer to an object or a member of an object that does not exist. The object cannot be constructed until the constructor's parameters get evaluated, first. C++ does not work this way.
You will need to come up with some alternative mechanism for your class. At which point you will discover another fatal design flaw that dooms the shown approach:
int (*funcPtr)(int);
This is a plain function pointer. In order for lambda to reference an object that it's related to, in some form or fashion, it must capture the object (by reference, most likely). However lambdas that capture (by value or reference), cannot be converted to a plain function pointer. Only capture-less lambdas can be converted to a plain pointer.
At the bare minimum this must be a std::function, instead.
And now that it's a std::function, you can capture its object, by reference, in the lambda, and assign it to the std::function.
But this is not all, there is another problem that you must deal with: in order for all of this to work it is no longer possible for the object to be moved or copied in any way. This is because the lambda captured a reference to the original object that was constructed, full stop.
And the fact that the constructed object gets copied or moved does not, in some form or fashion, modify the lambda so it now magically captures the reference to the copy or the moved instance of the original object.
None of these are insurmountable problems, but they will require quite a bit of work to address, in order to have a well-formed C++ program as a result.

Why would you explicitly move a forwarding reference?

I'm looking at some code, and I see the following function:
template <typename... Args>
static return_t make_return(Args &&... args)
{
// using std::forward<Args> will preserve lvalue args as such, but the point of this function
// is to make a return, where the 99.9+% case is moving a local (lvalue) into the return pack.
// Thus it forces a move, which will move `T&` args (but _not_ `const T&` args) into the
// return pack so that users don't need to type out a bunch of std::moves themselves/
// If they don't want implicit move they can just call std::make_tuple directly
return std::make_tuple(std::move(args)...);
}
The documentation here confuses me.
Why would you explicitly move a forwarding reference?
Wouldn't you want to preserve the lvalue / rvalue within a generic context?
I'm having trouble understanding the rationale or how this behavior would be different from the recommended std::forward.
To put it another way,
I've never seen anyone explicitly opt-out from perfectly-forwarding a forwarding reference.
Does it make sense?
Why would you explicitly move a forwarding reference?
Because it isn't being used for its forwarding properties. Yes, you are correct, we usually std::forward a forwarding reference. But in this case the author used forwarding references solely as a matter of convenience. If it was written as make_return(Args&... args) then it would be impossible to pass an rvalue to make_return, since a non-const lvalue reference may not bind to one.
By using forwarding references, the author allows passing values of any value category into the function, without incurring extra copies if none are needed. The documentation is there to clarify that the function signature isn't for forwarding, but simply for binding to whatever arguments it's given to move out.
A small example reveals the author's intent:
#include <tuple>
#include <iostream>
struct A {
A() { }
A(const A&) { std::cout << "copy\n"; }
A(A&&) { std::cout << "move\n"; }
};
template <typename Arg>
static std::tuple<A> make_return(Arg&& arg) {
return std::make_tuple(std::move(arg));
}
void f(const std::tuple<A>&) { }
void f1() {
std::cout << "return local via make_tuple: ";
A a{};
f(std::make_tuple(a));
}
void f2() {
std::cout << "return local via make_tuple(move): ";
A a{};
f(std::make_tuple(std::move(a)));
}
void f3() {
std::cout << "return local via make_return: ";
A a{};
f(make_return(a));
}
void f4() {
std::cout << "return const via make_tuple: ";
const A a{};
f(std::make_tuple(a));
}
void f5() {
std::cout << "return const via make_tuple(move): ";
const A a{};
f(std::make_tuple(std::move(a)));
}
void f6() {
std::cout << "return const via make_return: ";
const A a{};
f(make_return(a));
}
int main() {
f1();
f2();
f3();
f4();
f5();
f6();
}
Output:
return local via make_tuple: copy
return local via make_tuple(move): move
return local via make_return: move
return const via make_tuple: copy
return const via make_tuple(move): copy
return const via make_return: copy
In cases where a local non-const variable is returned, we want to std::move its contents. This is achievable using std::make_tuple(std::move(a)), because a plain std::make_tuple(a) would copy. To save some typing, the author wrote make_return as a shorthand for std::make_tuple(std::move(a)): the example shows that f3 works just like f2.
When a constant is passed, std::move won't make any difference, but no harm either. So we could use std::make_tuple, but make_return works just fine, too. Cases f4, f5, f6 all behave the same, showing that one doesn't really need to think twice before mixing constants and non-constants in make_return (in the case of multiple entries constituting return_t).
What remains is moving a non-const variable that is not local to the function, and thus we wouldn't like to destroy its contents. In these cases make_return is unwanted and one would need to resort back to manual invocation of std::make_tuple (utilizing std::move where appropriate only).
Now what would this look like with std::forward? Changing the definition of make_return to utilizing
std::make_tuple(std::forward<Arg>(arg));
produces:
return local via tuple: copy
return local via tuple(move): move
return local via make_return: copy
return const via tuple: copy
return const via tuple(move): copy
return const via make_return: copy
since a in f3 gets passed as a const A&. Indeed, make_return is then, by the logic of forwarding, a mere synonyme for std::move, losing any benefit we hoped to achieve.
make_return() is to return a tuple using a value, since this value won't be needed anymore, as is used in make_return (end scope of the a function), there's no need to use std::forward<>, since it could forward lvalue references which incurs in copies (depending on implementation), but value is at the end of scope so is not needed to preserve any resources.
Forcing std::move on the make_tuple, forces to use rvalue references first, omitting possible more overhead (depending on implementation).

c++ variant class member stored by reference

I am trying to experiment with std::variant. I am storing an std::variant as a member of a class. In the below code, things work fine if the variant is stored by value, but does not work (for the vector case, and for custom objects too) if the variant is stored by reference. Why is that?
#include <variant>
#include <vector>
#include <iostream>
template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;
struct Print {
void operator()(int v) { std::cout << "type = int, value = " << v << "\n"; }
void operator()(std::vector<int> v) const { std::cout << "type = vector<int>, size = " << v.size() << "\n"; }
};
class A {
public:
explicit A(const VectorOrSimple<int>& arg) : member(arg) {
print();
}
inline void print() const {
visit(Print{}, member);
}
private:
const VectorOrSimple<int> member; // const VectorOrSimple<int>& member; => does not work
};
int main() {
int simple = 1;
A a1(simple);
a1.print();
std::vector<int> vector(3, 1);
A a2(vector);
a2.print();
}
See http://melpon.org/wandbox/permlink/vhnkAnZhqgoYxU1H for a working version, and http://melpon.org/wandbox/permlink/T5RCx0ImTLi4gk5e for a crashing version with error : "terminate called after throwing an instance of 'std::bad_variant_access'
what(): Unexpected index"
Strangely, when writing a boost::variant version of the code with the member stored as a reference, it works as expected (prints vector size = 3 twice) with gcc7.0 (see here http://melpon.org/wandbox/permlink/eW3Bs1InG383vp6M) and does not work (prints vector size = 3 in constructor and then vector size = 0 on the subsequent print() call, but no crash) with clang 4.0 (see here http://melpon.org/wandbox/permlink/2GRf2y8RproD7XDM).
This is quite confusing. Can someone explain what is going on?
Thanks.
It doesn't work because this statement A a1(simple); creates a temporary variant object!
You then proceed to bind said temporary to your const reference. But the temporary goes out of scope immediately after the construction of a1 is over, leaving you with a dangling reference. Creating a copy works, obviously, since it always involves working with a valid copy.
A possible solution (if the performance of always copying worries you) is to accept a variant object by-value, and then move it into your local copy, like so:
explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
print();
}
This will allow your constructor to be called with either lvalues or rvalues. For lvalues your member will be initialized by moving a copy of the source variant, and for rvalues the contents of the source will just be moved (at most) twice.
Variants are objects. They contain one of a set of types, but they are not one of those types.
A reference to a variant is a reference to the variant object, not a reference to one of the contained types.
A variant of reference wrappers may be what you want:
template<class...Ts>
using variant_ref=std::variant<std::reference_wrapper<Ts>...>;
template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleRef = variant_ref<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleConstRef = variant_ref<const T, const std::vector<T>>;
Now store VectorOfSimpleConstRef<int>. (Not const&). And take one in the constructor as well.
Also modify Print to take by const& to avoid needlessly copying that std::vector when printing.

Cannot understand why perfect forwarding is not working

I am trying to understand how perfect forwarding works but I cannot understand why the copy constructor is called in the code below
#include <utility>
#include <iostream>
using std::cout;
using std::endl;
class Something {
public:
Something() = default;
Something(__attribute__((unused)) const Something& other) {
cout << "Copy constructor called" << endl;
}
Something(__attribute__((unused)) Something&& other) {
cout << "Move constructor called" << endl;
}
void print() {
cout << "Something::print() called" << endl;
}
};
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
void function_1(const Something& one) {
Something inner(one);
inner.print();
}
template <typename... T>
void test_function(T&&... ts) {
function_1(std::forward<T>(ts)...);
}
int main() {
const Something some1 {Something()};
test_function(some1);
test_function(Something());
return 0;
}
This produces the following output
Copy constructor called
Something::print() called
version two called
Copy constructor called
Something::print() called
Changing the code to include std::move in the rvalue reference works but I did not expect to need it. When a reference is an rvalue reference the correct constructor should be called automatically right? The correct reference is resolved but the wrong constructor is being called. Any help would be greatly appreciated!
An rvalue reference binds to rvalues. It is not itself an rvalue, for it has a name.
But anything with a name at point of use is an lvalue by default, even rvalue references. Your code could use Something&& one three times, and if the first use implicitly moves you would be screwed.
Instead, it is an lvalue at point of use (by default), and it binds to an rvalue.
When you want to signal you no longer require its state to persist, std::move it.
Perfect forwarding can be used to write both of your function_1s by putting a std::forward<Blah>(blah) at the point where you'd want to move from blah if it was an rvalue reference.
Now the above is full of lies, for there are xvalues prvalues lvalues etc -- the standard is more complex. The use of a variable in return statements can turn a named value into an rvalue, for example. But the basic rule of thumb is worth knowing: it has a name, it is an lvalue (except if explicitly casted, or expiring).
This code will call the copy ctor, not the move ctor.
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{one};
inner.print();
}
This code calls the move ctor.
void function_1(Something&& one) {
cout << "version two called" << endl;
Something inner{std::move(one)};
inner.print();
}
The expression one is technically an l-value. It refers to an rvalue-reference. But to actually get the rvalue-reference you have to use std::move. Generally anything that has a name is an l-value. Unnamed temporaries, like your Something() expression in main():
test_function(Something());
can be rvalue's and can invoke a move without using std::move.