What can I do with a moved-from object?
Moved-from objects exist in an unspecified, but valid, state. That suggests that whilst the object might not be capable of doing much anymore, all of its member functions should still exhibit defined behaviour — including operator=
— and all its members in a defined state- and it still requires destruction. The Standard gives no specific definitions because it would be unique to each UDT, but you might be able to find specifications for Standard types. Some like containers are relatively obvious — they just move their contents around and an empty container is a well-defined valid state. Primitives don't modify the moved-from object.
Side note: I believe it's T c = std::move(a)
so that if the move constructor (or copy constructor if no move is provided) is explicit the function will fail.
What is technically a moved-from object?
Well, std::move(x);
is simply casting to r-value reference - it doesn't do anything. But OK, assume you had this:
int x = 42;
int z = std::move(x);
int y = x; // is this ok?
Yes, it is OK and x, y, z
will all be 42. Because for trivial types moving is the same as copying.
But what of other more complex classes?
In general, there are only a few strict requirements for moving and move-from objects.
- moved-from object needs be copy/move assignable and destructible.
- target should be "equal" to pre-moved source.
These requirements are necessary. A lot of STL functionality and other libraries will not operate properly with types that fail to support these.
In practice, simple POD types simply perform a copy on move while containers transfer resource ownership from source to target while destroying whatever resources target owned. Technically, data swap between the objects is also a legitimate action - and some believe it to be a good idea - I strongly disagree with it because if I wanted to swap data then I'd trigger std::swap
instead of std::move
.
Nevertheless, there is no strict requirement what move must do to moved-from objects - which is important when dealing with complex classes. For instance, one can write a custom allocator for std::vector
that will explicitly forbid to move, in which case on move some sort of data copying mixed with data moving will take place and different versions of STL may or may not clear original object.
Notes: cppreference has explicitly stated requirements on moved-from objects for majority of classes in the documentation. So you'd know what exactly what to expect and it's not always intuitive. Usually they go for the laziest action possible.
What constitutes a valid state for a moved from object in C++11?
You define and document for your types what a 'valid' state is and what operation can be performed on moved-from objects of your types.
Moving an object of a standard library type puts the object into an unspecified state, which can be queried as normal to determine valid operations.
17.6.5.15 Moved-from state of library types
[lib.types.movedfrom]Objects of types defined in the C++ standard library may be moved from
(12.8). Move operations may be explicitly specified or implicitly
generated. Unless otherwise specified, such moved-from objects shall
be placed in a valid but unspecified state.
The object being in a 'valid' state means that all the requirements the standard specifies for the type still hold true. That means you can use any operation on a moved-from, standard library type for which the preconditions hold true.
Normally the state of an object is known so you don't have to check if it meets the preconditions for each operation you want to perform. The only difference with moved-from objects is that you don't know the state, so you do have to check. For example, you should not pop_back() on a moved-from string until you have queried the state of the string to determine that the preconditions of pop_back() are met.
std::string s = "foo";
std::string t(std::move(s));
if (!s.empty()) // empty has no preconditions, so it's safe to call on moved-from objects
s.pop_back(); // after verifying that the preconditions are met, pop_back is safe to call on moved-from objects
The state is probably unspecified because it would be onerous to create a single useful set of requirements for all different implementations of the standard library.
Since you are responsible not only for the specification but also the implementation of your types, you can simply specify the state and obviate the need for querying. For example it would be perfectly reasonable to specify that moving from your pimpl type object causes do_stuff to become an invalid operation with undefined behavior (via dereferencing a null pointer). The language is designed such that moving only occurs either when it's not possible to do anything to the moved-from object, or when the user has very obviously and very explicitly indicated a move operation, so a user should never be surprised by a moved-from object.
Also note that the 'concepts' defined by the standard library do not make any allowances for moved-from objects. That means that in order to meet the requirements for any of the concepts defined by the standard library, moved-from objects of your types must still fulfill the concept requirements. This means that if objects of your type don't remain in a valid state (as defined by the relevant concept) then you cannot use it with the standard library (or the result is undefined behavior).
What is a state of an object after it was moved-from via a reference to its base class?
The standard does not make any such requirement on move constructors for C++ classes that are not a part of the standard library. The library writer is free to do what they want. For components that are a part of the standard library, the C++17 standard does say something (emphasis mine)
§ 20.5.5.15 Moved-from state of library types [lib.types.movedfrom]
Objects of types defined in the C++ standard library may be moved from (15.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.
For classes in the standard library that are a part of an inheritance hierarchy, you would have to consult the documentation to see what happens when you try and move construct a base object from a base class rvalue reference a derived class object. So if you could specify which class in particular you were worried about I could try and help more.
Not sure how relevant this is to your question, but regarding what would really happen in such a constructor. Remember that the virtual function mechanism is disabled in constructors for the object that is going to be constructed, but not for the referenced object. In the following example
class Base {
public:
virtual vector<int> extract_vector() { ... }
// Move constructor can use virtual functions on the other object
Base(Base&& other) {
this->vec = other.extract_vector();
}
private:
std::vector<int> vec;
};
class Foo : public Base {
public:
vector<int> extract_vector() override { ... }
private:
// this does something ¯\\_(ツ)_/¯
SpecialVectorAdaptor<std::vector<int>> vec;
};
The virtual function extract_vector
on other
in the move constructor for Base
will be called, and you can utilize virtual methods on the other
object. But you cannot use any such virtual methods on the class that is going to be constructed.
So long story short, the behavior of the code you have shown will depend strictly on the implementation of the classes in question.
How can moved objects be used? [duplicate]
Yes, you can move another object into it. std::swap does this.
Moved objects are still destructed?
Yes, moved-from objects are destructed. They remain in an undetermined but valid state. They're still objects.
It's best if you recall that C++ doesn't actually move anything. std::move
just gives you an rvalue. So-called "move constructors" are just convenient alternatives to copy constructors, found during lookup when you have an rvalue, and allowing you the opportunity to swap your class's encapsulated data rather than actually copying it. But C++ doesn't move anything for you, and it can't tell when you have done some moving.
As such, it would be infeasibly dangerous and impractical for C++ to have any kind of rule that somehow stopped "moved-from" objects, if we could even decide what this meant in general, from later undergoing destruction. Make this destruction safe (a no-op, ideally) for your moved-from objects (e.g. by setting source pointers to nullptr
in your move constructor) and you'll be fine.
What does explicitly-defaulted move constructor do?
What does explicitly-defaulted move constructor do?
It will initialize its member variables with the corresponding member variables in the moved from object after turning them into xvalues. This is the same as if you use std::move
in your own implementation:
Base(Base&& other) noexcept : id(std::move(other.id)) {}
Note though that for fundamental types, like int
, this is no different from copying the value. If you want the moved from object to have its id
set to 0
, use std::exchange
:
Base(Base&& other) noexcept : id(std::exchange(other.id, 0)) {}
Base& operator=(Base&& other) noexcept {
if(this != &other) id = std::exchange(other.id, 0);
return *this;
}
With that, the Foo
move constructor and move assignment operator can be default
ed and "do the right thing".
Suggestion: I think Base
would benefit from a constructor that can initialize id
directly. Example:
Base(int Id) : id(Id) {
std::cout << "Base() called " << id << std::endl;
}
Base() : Base(0) {} // delegate to the above
Now, the Foo
constructor taking an id as an argument could look like this:
Foo(int Id) : Base(Id) {
std::cout << "Foo() called " << id << std::endl;
}
c++ reassign after moved
This is guaranteed. After the move, the vector
is guaranteed to be empty, i.e. has no elements. It's fine to be assigned by other contents.
After the move,
other
is guaranteed to beempty()
.
Related Topics
How to Fill an Array With Random Values from a Range
How to Determine the Highest and Lowest Value Using Do While Loops
Print Heart Shape With Words Inside
Get Current Time in Milliseconds, or Hh:Mm:Ss:Mmm Format
Invalid Operands Error for Addition and Integer Division
Vector of Structs Initialization
Writing a Sequence of Numbers Like: 1 22 333 4444 55555
Most Efficient Way to Find the Greatest of Three Ints
C++: Modifying Array Via Function
How to Read Unknown Number of Inputs
Sorting Output Numbers Without an Array
Difference Between 'Typedef' and 'Using' in C++11
Why Use Static_Cast≪Int≫(X) Instead of (Int)X
How Does Delete[] "Know" the Size of the Operand Array