Does std::is_move_constructible<T>::value == true
imply that T
has a usable move constructor?
If so, what is the default behaviour of it?
Consider the following case:
struct foo {
int* ptr;
};
int main() {
{
std::cout << std::is_move_constructible<foo>::value << '\n';
foo f;
f.ptr = (int*)12;
foo f2(std::move(f));
std::cout << f.ptr << ' ' << f2.ptr << '\n';
}
return 0;
}
and the output is:
1
0000000C 0000000C
I thought that f.ptr
should be nullptr
.
So in this case,
f2
move constructed ?(I'm using VS11.)
The default behaviour of move constructor is same as a copy constructor, is it correct? If it's true,
It seems that foo f2(std::move(f));
calls the copy ctor when I declared one, see:
struct foo {
int* ptr;
foo() {}
foo(const foo& other) {
std::cout << "copy constructed\n";
}
};
int main() {
{
std::cout << std::is_move_constructible<foo>::value << '\n';
foo f;
foo f2(std::move(f));
}
system("pause");
return 0;
}
Now the output is:
1
copy constructed
If foo
has a move constructor, then wouldn't foo f2(std::move(f))
call it?
So now my questions is: How to know if a class has a move ctor, and if it has one, how can I explicitly call it?
template<typename T, bool has_move_ctor>
struct MoveAux;
template<typename T>
struct MoveAux<T, true> {
static void doMove(T* dest, T* src) {
new(dest) T(std::move(*src)); //move ctor
}
};
template<typename T>
struct MoveAux<T, false> {
static void doMove(T* dest, T* src) {
new(dest) T(*src); //copy ctor
src->~T();
}
};
template<typename T>
inline doMove(T* dest, T* src) {
MoveAux<T,/*a trait*/>::doMove(dest, src);
}
So I thought std::is_move_constructible<T>::value
can be passed to the template, while now I see that this trait only cares if T t(T())
is a valid expression, it may call T::T(const T&)
.
Now assume that T
is a custom class, then I want the above templates to behave like:
MoveAux<T,false>::doMove
.MoveAux<T,true>::doMove
.Is it possible to make this work?
does
std::is_move_constructible<T>::value == true
implies thatT
has a usable move constructor?
Either a move constructor or a copy constructor. Remember that the operation of copy construction satisfies all the requirements that are placed upon the operation move construction, and some more.
In Standard terms, a MoveConstructible
object is one for which the evaluation of the expression:
T u = rv;
makes u
equivalent to the value of rv
before the construction; the state of rv
after being moved-from is unspecified. But since it is unspecified, this means the state could even be identical to the one rv
had before being moved from: In other words, u
could be a copy of rv
.
In fact, the Standard defines the CopyConstructible
concept to be a refinement of the MoveConstructible
concept (so everything which is CopyConstructible
is also MoveConstructible
, but not vice versa).
if so, what is the default behaviour of it?
The behavior of an implicitly generated move constructor is to perform a member-wise move of the data members of the type for which it is generated.
Per Parahgraph 12.8/15 of the C++11 Standard:
The implicitly-defined copy/move constructor for a non-union class
X
performs a memberwise copy/move of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ]
Moreover:
1 - is
f2
move constructed ?
Yes.
2 - if so, shouldn't the rvalue be invalidated?
Moving a pointer is the same as copying it. So no invalidation is going on, neither should it be going on. If you want a move constructor that leaves the moved-from object in a particular state (i.e. sets a pointer data member to nullptr
), you have to write your own - or delegate this responsibility to some smart pointer class such as std::unique_ptr
.
Notice, that the word "invalidated" is not quite correct here. Move constructors (as well as move assignment operators) are meant to leave the moved-from object in a valid (yet unspecified) state.
In other words, the class invariant needs to be respected - and it should be possible to invoke on a moved-from objects operations that do not have any precondition on its state (usually, destruction and assignment).