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,
- Is
f2move constructed ? - If so, shouldn't the rvalue be invalidated?
- How can I know if instances of a class can be properly move-constructed (invalidate the old one)?
(I'm using VS11.)
Update
The default behaviour of move constructor is same as a copy constructor, is it correct? If it's true,
- We always expect a move ctor to steal the resources of the moved-from object, while the default one does not behave as expected, so what's the point of having a default move ctor?
- How can I know if a class has a custom move constructor (which can be guaranteed to behave properly)?
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?
What I'm trying to do is…
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:
- If I don't declare a move ctor, I want that template method calls the
MoveAux<T,false>::doMove. - If I declared one, I need it calls to
MoveAux<T,true>::doMove.
Is it possible to make this work?
move, you may not access any of its members". It's not even true that after moving from an object, you may not access any of its members. The effect of moving from a primitive type is to leave it unchanged. Class types can decide for themselves the effect of moving -- standard library classes mostly say that the object is left in an indeterminate but valid state, and in general at least the destructor needs to work, which means any members accessed by the destructor are going to have to hold sensible values.