Passing a movable object - c++

Reading an answer in SO, he passed a vector with move. I thought the correct way is to pass it simple without using move:
class B
{
std::vector<T> data;
public:
B(std::vector<T> p) : data(std::move(p)) {}
^^^^^^^^^^^^
?
};
The second way is:
class B
{
std::vector<T> data;
public:
B(std::vector<T> p) : data(p) {}
};
Which one is correct?

The function argument is already taken by value, so a copy will already have been made. The local object p is unquestioningly yours and yours alone, so you can move from it unconditionally.
The beauty of taking the argument by value is that it works for both lvalues and rvalues: For lvalues you make a genuine copy, since there's nothing else you can do, but for rvalues the function argument itself can be constructed by moving, so there's only one expensive construction happening ever, and everything else is moved.

When you construct an object from an lvalue, it will be copied. When you construct an object from a non-const rvalue it can be moved (whether it will be moved depends on the class having a move constructor). In the context of your constructor, p is clearly a lvalue: it has a name. However, it is a local variable and about to go away, i.e., it is save to move from it: std::move(p) makes the object appear as if it is an rvalue: in this context, std::move()ing the value is the right way to go.
Note that the recommendations are different if you return an object: a local value returned in a return statement is automatically moved from. Using std::move() would just reinforce the statement but would also inhibit the possibility of eliding the copy/move entirely. In your constructor the copy/move cannot be elided because copy elision only works with temporary objects or with local objects in return statements.
T f() {
T local;
return local; // good: elided, moved, or copied in this order of preference
}
T g() {
T local;
return std::move(local); // bad: can't be elided and will be moved or copied
}

Related

C++ class member rvalue assignment

I have seen C++ code that assigns a class member using an std::move call on an rvalue as follows:
class Widget {
std::vector<int> m_data{};
public:
// 1. OK
// x contents are copied locally, m_data space is extended if necessary
void set_data(const std::vector<int>& x) {
m_data = x;
}
// 2. x creates an rvalue that is moved into m_data. What if Widget is dynamically allocated?
void set_data(std::vector<int> x) {
m_data = std::move(x);
}
// 3. x is an rvalue generated before the call. What if Widget is dynamically allocated?
void set_data(std::vector<int>&& x) noexcept {
m_data = std::move(x);
}
};
Widget* pW = new Widget{};
pW->setData(std::vector<int>{1, 2, 3});
I don't understand 2 and 3. How is it possible to safely move an rvalue to a class member if the scope of Widget is not the same than the rvalue passed to set_value()?
EDIT: Fixed my code after user17732522 pointed out that the original version was passing an lvalue, not an rvalue to pW->setData();
std::move does not affect the lifetime of the moved object itself. Instead it indicates that ownership over resources owned by the object on which std::move is called may/should be taken over by the function to which std::move(/*...*/) is an argument.
For example for a std::vector moving the object means that the destination vector should take over any dynamic memory allocations made by the source vector containing the vector elements, so that the source vector's state after the move will be that of an empty vector and the state of the destination vector will be that of the source before the move without any allocation or copying of elements needing to take place. The vector objects themselves are not otherwise affected.
std::move on a type that doesn't own any resources, e.g. a simple std::pair<int, float>, has no effect. It will simply result in a copy as without move semantics.
Whether the object is instantiated in dynamic scope, or not, is completely immaterial as far as move semantics getting used, or not, when passing parameters for an invokation of the object's method, and whether or not the object's methods use move semantics inside the method. It is completely irrelevant.
Whether or not undefined behavior results from usage or non-usage of move semantisc will be determined by factors that are not necessarily relevant to the object's scope.
void set_data(std::vector<int> x) {
m_data = std::move(x);
}
In this case, the method caller's is responsible for using move semantics for set_data()'s parameter. Failure to do so will result in the parameter, presumably, getting copy-constructed. Whatever the case may be, it is immaterial when it comes to move-assignment that takes place when assigning m_data from the passed-in parameter. This will happen irregardless of how set_data() gets invoked. The method has no knowledge of how the parameter got passed in.
void set_data(std::vector<int>&& x) noexcept {
m_data = std::move(x);
}
Here, the caller is responsible for producing a movable rvalue reference. Attempting to pass an lvalue, which would produce a loss of move semantics, results in ill-formed code. This, effectively, forces the caller into employing move semantics when calling this method.
How is it possible to safely move an rvalue to a class member if the scope of Widget is not the same than the rvalue passed to set_value()?
Again, it is immaterial. Whether Widgetexists in dynamic scope, or not, is immaterial as far as move semantics related to calling the object's methods. It may or may not indirectly affect whether or not the totality of the object's method calls results in undefined behavior, or not, but the move semantics themselves have no relation to the scope of the object itself.

Perfect forwarding and constructors

I am trying to understand the interaction of perfect forwarding and constructors. My example is the following:
#include <utility>
#include <iostream>
template<typename A, typename B>
using disable_if_same_or_derived =
std::enable_if_t<
!std::is_base_of<
A,
std::remove_reference_t<B>
>::value
>;
template<class T>
class wrapper {
public:
// perfect forwarding ctor in order not to copy or move if unnecessary
template<
class T0,
class = disable_if_same_or_derived<wrapper,T0> // do not use this instead of the copy ctor
> explicit
wrapper(T0&& x)
: x(std::forward<T0>(x))
{}
private:
T x;
};
class trace {
public:
trace() {}
trace(const trace&) { std::cout << "copy ctor\n"; }
trace& operator=(const trace&) { std::cout << "copy assign\n"; return *this; }
trace(trace&&) { std::cout << "move ctor\n"; }
trace& operator=(trace&&) { std::cout << "move assign\n"; return *this; }
};
int main() {
trace t1;
wrapper<trace> w_1 {t1}; // prints "copy ctor": OK
trace t2;
wrapper<trace> w_2 {std::move(t2)}; // prints "move ctor": OK
wrapper<trace> w_3 {trace()}; // prints "move ctor": why?
}
I want my wrapper to have no overhead at all. In particular, when marshalling a temporary into the wrapper, as with w_3, I would expect the trace object to be created directly in place, without having to call the move ctor. However, there is a move ctor call, which makes me think a temporary is created and then moved from. Why is the move ctor called? How not to call it?
I would expect the trace object to be created directly in place,
without having to call the move ctor.
I don't know why you expect that. Forwarding does exactly this: moves or copies 1). In your example you create a temporary with trace() and then the forwarding moves it into x
If you want to construct a T object in place then you need to pass the arguments to the construction of T, not an T object to be moved or copied.
Create an in place constructor:
template <class... Args>
wrapper(std::in_place_t, Args&&... args)
:x{std::forward<Args>(args)...}
{}
And then call it like this:
wrapper<trace> w_3 {std::in_place};
// or if you need to construct an `trace` object with arguments;
wrapper<trace> w_3 {std::in_place, a1, a2, a3};
Addressing a comment from the OP on another answer:
#bolov Lets forget perfect forwarding for a minute. I think the
problem is that I want an object to be constructed at its final
destination. Now if it is not in the constructor, it is now garanteed
to happen with the garanteed copy/move elision (here move and copy are
almost the same). What I don't understand is why this would not be
possible in the constructor. My test case proves it does not happen
according to the current standard, but I don't think this should be
impossible to specify by the standard and implement by compilers. What
do I miss that is so special about the ctor?
There is absolutely nothing special about a ctor in this regard. You can see the exact same behavior with a simple free function:
template <class T>
auto simple_function(T&& a)
{
X x = std::forward<T>(a);
// ^ guaranteed copy or move (depending on what kind of argument is provided
}
auto test()
{
simple_function(X{});
}
The above example is similar with your OP. You can see simple_function as analog to your wrapper constructor and my local x variable as analog to your data member in wrapper. The mechanism is the same in this regard.
In order to understand why you can't construct the object directly in the local scope of simple_function (or as data member in your wrapper object in your case) you need to understand how guaranteed copy elision works in C++17 I recommend this excelent answer.
To sum up that answer: basically a prvalue expression doesn't materializez an object, instead it is something that can initialize an object. You hold on to the expression for as long as possible before you use it to initialize an object (thus avoiding some copy/moves). Refer to the linked answer for a more in-depth yet friendly explanation.
The moment your expression is used to initialize the parameter of simple_foo (or the parameter of your constructor) you are forced to materialize an object and lose your expression. From now on you don't have the original prvalue expression anymore, you have a created materialized object. And this object now needs to be moved into your final destination - my local x (or your data member x).
If we modify my example a bit we can see guaranteed copy elision at work:
auto simple_function(X a)
{
X x = a;
X x2 = std::move(a);
}
auto test()
{
simple_function(X{});
}
Without elision things would go like this:
X{} creates a temporary object as argument for simple_function. Lets call it Temp1
Temp1 is now moved (because it is a prvalue) into the parameter a of simple_function
a is copied (because a is an lvalue) into x
a is moved (because std::move casts a to an xvalue) to x2
Now with C++17 guaranteed copy elision
X{} no longer materializez an object on the spot. Instead the expression is held onto.
the parameter a of simple_function can now by initialized from the X{} expression. No copy or move involved nor required.
The rest is now the same:
a is copied into x1
a is moved into x2
What you need to understand: once you have named something, that something must exist. The surprisingly simple reason for that is that once you have a name for something you can reference it multiple times. See my answer on this other question. You have named the parameter of wrapper::wrapper. I have named the parameter of simple_function. That is the moment you lose your prvalue expression to initialize that named object.
If you want to use the C++17 guaranteed copy elision and you don't like the in-place method you need to avoid naming things :) You can do that with a lambda. The idiom I see most often, including in the standard, is the in-place way. Since I haven't seen the lambda way in the wild, I don't know if I would recommend it. Here it is anyway:
template<class T> class wrapper {
public:
template <class F>
wrapper(F initializer)
: x{initializer()}
{}
private:
T x;
};
auto test()
{
wrapper<X> w = [] { return X{};};
}
In C++17 this grantees no copies and/or moves and that it works even if X has deleted copy constructors and move constructors. The object will be constructed at it's final destination, just like you want.
1) I am talking about the forwarding idiom, when used properly. std::forward is just a cast.
A reference (either lvalue reference or rvalue reference) must be bound to an object, so when the reference parameter x is initialized, a temporary object is required to be materialized anyway. In this sense, perfect forwarding is not that "perfect".
Technically, to elide this move, the compiler must know both the initializer argument and the definition of the constructor. This is impossible because they may lie in different translation units.

Does D have a move constructor?

I am referencing this SO answer Does D have something akin to C++0x's move semantics?
Next, you can override C++'s constructor(constructor &&that) by defining this(Struct that). Likewise, you can override the assign with opAssign(Struct that). In both cases, you need to make sure that you destroy the values of that.
He gives an example like this:
// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
Will the variable that always get moved? Or could it happen that the variable that could get copied in some situations?
It would be unfortunate if I would only null the ptr on a temporary copy.
Well, you can also take a look at this SO question:
Questions about postblit and move semantics
The way that a struct is copied in D is that its memory is blitted, and then if it has a postblit constructor, its postblit constructor is called. And if the compiler determines that a copy isn't actually necessary, then it will just not call the postblit constructor and will not call the destructor on the original object. So, it will have moved the object rather than copy it.
In particular, according to TDPL (p.251), the language guarantees that
All anonymous rvalues are moved, not copied. A call to this(this)
is never inserted when the source is an anonymous rvalue (i.e., a
temporary as featured in the function hun above).
All named temporaries that are stack-allocated inside a function and
then returned elide a call to this(this).
There is no guarantee that other potential elisions are observed.
So, in other cases, the compiler may or may not elide copies, depending on the current compiler implementation and optimization level (e.g. if you pass an lvalue to a function that takes it by value, and that variable is never referenced again after the function call).
So, if you have
void foo(Bar bar)
{}
then whether the argument to foo gets moved or not depends on whether it was an rvalue or an lvalue. If it's an rvalue, it will be moved, whereas if it's an lvalue, it probably won't be (but might depending on the calling code and the compiler).
So, if you have
void foo(UniquePtr!T ptr)
{}
ptr will be moved if foo was passed an rvalue and may or may not be moved it it's passed an lvalue (though generally not). So, what happens with the internals of UniquePtr depends on how you implemented it. If UniquePtr disabled the postblit constructor so that it can't be copied, then passing an rvalue will move the argument, and passing an lvalue will result in a compilation error (since the rvalue is guaranteed to be moved, whereas the lvalue is not).
Now, what you have is
this(UniquePtr!T that)
{
this.ptr = that.ptr;
that.ptr = null;
}
which appears to act like the current type has the same members as those of its argument. So, I assume that what you're actually trying to do here is a copy constructor / move constructor for UniquePtr and not a constructor for an arbitrary type that takes a UniquePtr!T. And if that's what you're doing, then you'd want a postblit constructor - this(this) - and not one that takes the same type as the struct itself (since D does not have copy constructors). So, if what you want is a copy constructor, then you do something like
this(this)
{
// Do any deep copying you want here. e.g.
arr = arr.dup;
}
But if a bitwise copy of your struct's elements works for your type, then you don't need a postblit constructor. But moving is built-in, so you don't need to declare a move constructor regardless (a move will just blit the struct's members). Rather, if what you want is to guarantee that the object is moved and never copied, then what you want to do is disable the struct's postblit constructor. e.g.
#disable this(this);
Then any and all times that you pass a UniquePtr!T anywhere, it's guaranteed to be a move or a compilation error. And while I would have thought that you might have to disable opAssign separately to disable assignment, from the looks of it (based on the code that I just tested), you don't even have to disable assignment separately. Disabling the postblit constructor also disables the assignment operator. But if that weren't the case, then you'd just have to disable opOpAssign as well.
JMD answer covers theoretical part of move semantics, I can extend it with a very simplified example implementation:
struct UniquePtr(T)
{
private T* ptr;
#disable this(this);
UniquePtr release()
{
scope(exit) this.ptr = null;
return UniquePtr(this.ptr);
}
}
// some function that takes argument by value:
void foo ( UniquePtr!int ) { }
auto p = UniquePtr!int(new int);
// won't compile, postblit constructor is disabled
foo(p);
// ok, release() returns a new rvalue which is
// guaranteed to be moved without copying
foo(p.release());
// release also resets previous pointer:
assert(p.ptr is null);
I think I can answer it myself. Quoting the "The Programming Language":
All anonymous rvalues are moved, not copied. A call to this ( this ) is never inserted
when the source is an anonymous rvalue (i.e., a temporary as featured in
the function hun above).
If I understood it correctly, this means that this(Struct that) will never be a copy, because it only accepts rvalues in the first place.

Why isn't object returned by std::move destroyed immediately

I tested the following code:
#include <iostream>
using namespace std;
class foo{
public:
foo() {cout<<"foo()"<<endl;}
~foo() {cout<<"~foo()"<<endl;}
};
int main()
{
foo f;
move(f);
cout<<"statement \"move(f);\" done."<<endl;
return 0;
}
The output was:
foo()
statement "move(f);" done.
~foo()
However, I expected:
foo()
~foo()
statement "move(f);" done.
According to the source code of the function move:
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
The returned object is a right value, So Why isn't it destroyed immediately?
-----------------------------------------------------------------
I think I just confused rvalue and rvalue reference.
I modified my code:
#include <iostream>
template<typename _Tp>
constexpr typename /**/std::remove_reference<_Tp>::type /* no && */
/**/ mymove /**/ (_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
using namespace std;
class foo{
public:
foo() {cout<<"foo() at "<<this<<endl;} /* use address to trace different objects */
~foo() {cout<<"~foo() at "<<this<<endl;} /* use address to trace different objects */
};
int main()
{
foo f;
mymove(f);
cout<<"statement \"mymove(f);\" done."<<endl;
return 0;
}
And now I get what I've been expecting:
foo() at 0x22fefe
~foo() at 0x22feff
statement "mymove(f);" done.
~foo() at 0x22fefe
Moving from an object doesn't change its lifetime, only its current value. Your object foo is destroyed on return from main, which is after your output.
Futhermore, std::move doesn't move from the object. It just returns an rvalue reference whose referand is the object, making it possible to move from the object.
Objects get destroyed when they go out of scope. Moving from an object doesn't change that; depending on what the move constructor or move assignment operator does, the state of the object can be different after the move, but is hasn't yet been destroyed, so the practical rule is that moving from an object must leave it in a state that can be destroyed.
Beyond that, as #R.MartinhoFernandes points out, std::move doesn't do anything. It's the object's move constructor or move assignment operator that does whatever needs to be done, and that isn't applied in a call to std::move; it's applied when the moved-from object is used to construct a new object (move constructor) or is assigned to an existing object (move assignment operator). Like this:
foo f;
foo f1(f); // applies foo's copy constructor
foo f2(std::move(f)); // applies foo's move constructor
foo f3, f4;
f3 = f; // applies foo's copy assignment operator
f4 = std::move(f1); // applies foo's move assignment operator
A std::move doesn't change objects lifetime. Roughly speaking it's nothing more than a static_cast that casts a non const lvalue to a non const rvalue reference.
The usefulness of this is overload resolution. Indeed, some functions take parameters by const lvalue reference (e.g. copy constructors) and other take by non const rvalue reference (e.g. move constructors). If the passed object is a temporary, then the compiler calls the second overload. The idea is that just after the function is called the a temporary can no longer be used (and will be destroyed). Therefore the second overload could take ownership of the temporary's resources instead of coping them.
However, the compiler will not do it for a non-temporary object (or, to be more correct for an lvalue). The reason is that the passed object has a name that remains in scope and therefore is alive could still be used (as your code demonstrate). So its internal resources might still be required and it would be a problem if they have had been moved to the other object. Nevertheless, you can instruct the compiler that it can call the second overload by using std::move. It casts the argument to a rvalue reference and, by overload resolution, the second overload is called.
The slight changed code below illustrate this point.
#include <iostream>
using namespace std;
class foo{
public:
foo() { cout << "foo()" << endl; }
~foo() { cout << "~foo()" << endl; }
};
void g(const foo&) { cout << "lref" << endl; }
void g(foo&&) { cout << "rref" << endl; }
int main()
{
foo f;
g(f);
g(move(f));
// f is still in scope and can be referenced.
// For instance, we can call g(f) again.
// Imagine what would happen if f had been destroyed as the question's author
// originally though?
g(static_cast<foo&&>(f)); // This is equivalent to the previous line
cout<<"statement \"move(f);\" done."<<endl;
return 0;
}
The output is
foo()
lref
rref
rref
statement "move(f);" done.
~foo()
Update: (After the question has been changed to use mymove)
Notice that the new code doesn't give exactly what you said at the very beginning. Indeed it reports two calls to ~foo() rather than one.
From the displayed addresses we can see that the original object of type foo, namely, f is destroyed at the very end. Exactly as it used to be with the original code. As many have pointed out, f is destroyed only at the end of its scope (the body of function main). This is still the case.
The extra call to ~foo() reported just before the statement "mymove(f);" done. destroys another object which is a copy of f. If you add a reporting copy constructor to foo:
foo(const foo& orig) { cout << "copy foo from " << &orig << " to " << this << endl;}
Then you get an output similar to:
foo() at 0xa74203de
copy foo from 0xa74203de to 0xa74203df
~foo() at 0xa74203df
statement "move(f);" done.
~foo() at 0xa74203de
We can deduce that calling mymove yields a call to the copy constructor to copy f to another foo object. Then, this newly created object is destroyed before execution reaches the line that displays statement "move(f);" done.
The natural question now is where this copy come from? Well, notice the return type of mymove:
constexpr typename /**/std::remove_reference<_Tp>::type /* no && */`
In this example, after a simplification for clarity, this boils down to foo. That is, mymove returns a foo by value. Therefore, a copy is made to create a temporary object. As I said before, a temporary is destroyed just after the expression that creates it finishes to be evaluated (well, there are exceptions to this rule but they don't apply to this code). That explains the extra call to ~foo().
Because in the general case, the move could happen in another translation unit. In your example, the object wasn't even moved, only marked as movable. This means that the caller of std::move will not know if the object was moved or not, all he knows is, that there is an object and that it has to call the destructor at the end of the scope/lifetime of that object. std::move only marks the object as movable, it does not perform the move operation or create a moved copy that can be further moved or anything like that.
Consider:
// translation unit 1
void f( std::vector< int >&& v )
{
if( v.size() > 8 ) {
// move it
}
else {
// copy it as it's just a few entries
}
}
// translation unit 2
void f( std::vector< int >&& );
std::vector< int > g();
int main()
{
// v is created here
std::vector< int > v = g();
// it is maybe moved here
f( std::move( v ) );
// here, v still exists as an object
// when main() ends, it will be destroyed
}
In the example above, how would translation unit 2 decide whether or not to call the destructor after the std::move?
You're getting confused by the name -- std::move doesn't actually move anything. It just converts (casts) an lvalue reference into an rvalue reference, and is used to make someone else move something.
Where std::move is useful is when you have an overloaded function that takes either an lvalue or an rvalue reference. If you call such a function with a simple variable, overload resolution means you'll call the version with the lvalue reference. You can add an explicit call to std::move to instead call the rvalue reference version. No moves involved, except within the function that takes the rvalue reference.
Now the reason it is called move is the common usage where you have two constructors, one of which takes an lvalue reference (commonly called the copy constructor) and one that takes an rvalue reference (commonly called the move constructor). In this case, adding an explicit call to std::move means you call the move constructor instead of the copy constructor.
In the more general case, it's common practice to have overloaded functions that take lvalue/rvalue references where the lvalue version makes a copy of the object and the rvalue version moves the object (implicitly modifying the source object to take over any memory it uses).
Suppose code like this:
void bar(Foo& a) {
if (a.noLongerneeded())
lastUnneeded = std::move(a);
}
In this case, the caller of bar can not know that the function might in some cases end up calling the destructor of the passed object. It will feel responsible for that object, and make sure to call its destructor at any later point.
So the rule is that move may turn a valid object into a different but still valid object. Still valid means that calling methods or the destructor on that object should still yield well-defined results. Strictly speaking, move by itself does nothing except tell the receiver of such a reference that it may change the object if doing so makes sense. So it's the recipient, e.g. move constructor or move assignment operator, which does the actual moving. These operations will usually either not change the object at all, or set some pointers to nullptr, or some lengths to zero or something like that. They will however never call the destructor, since that task is left to the owner of the object.

Is there anything incorrect about "return std::move(*this);"?

I know that a certain object is only ever created as a temporary object (it's a private member object within a library). Sometimes, that object is further initialized by chaining member functions together (TempObj().Init("param").Init("other param")). I would like to enable move construction for another object using that temporary instance, and so I was wondering if there was anything incorrect about return std::move(*this).
struct TempObj
{
TempObj &&Member() { /* do stuff */ return std::move(*this); }
};
struct Foo
{
Foo(TempObj &&obj);
};
// typical usage:
Foo foo(TempObj().Member());
Is it functionally equivalent to this?
struct TempObj
{
TempObj(TempObj &&other);
TempObj Member() { /* do stuff */ return *this; }
};
Foo foo(TempObj().Member());
With move semantics, you don't want (or need) to return r-value references from functions ... r-value references are there to "capture" unnamed values or memory addresses. When you return a r-value reference to an object that is in-fact an l-value from the standpoint of the caller, the semantics are all wrong, and you create the opportunity for needless surprises to arise when others are using your object's methods.
In other words, it would be better to orient your code to look like this:
Foo foo(std::move(TempObj().Member()));
and have TempObj::Member simply return a l-value reference. This makes the move explicit, and there are no suprises involved for someone using your object's methods.
Finally, no, it's not functionally or semantically equivalent to your last example. There you are actually making a temporary copy of the object, and that copy will be an r-value object (i.e., an unamed object in this scenario) ... since the assumption with r-value references is that the object is either an unamed value or object, and it can therefore be harmlessly modified by a function you pass it to that takes an r-value reference argument. On the other-hand, if you've passed a copy of an object to a function, then the function cannot modify the original. It will simply modify the referenced temporary r-value, and when the function exits, the temporary r-value copy of the object will be destroyed.