Имеет ли std::is_move_constructible<T>::value == true
, что T
имеет полезный конструктор перемещения?
Если да, то каково его поведение по умолчанию?
Рассмотрим следующий случай:
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;
}
а выход:
1
0000000C 0000000C
Я думал, что f.ptr
должен быть nullptr
.
Итак, в этом случае
- Строка
f2
построена? - Если это так, не следует ли признавать значение rvalue?
- Как узнать, могут ли экземпляры класса корректно перемещаться (недействительны старые)?
(Я использую VS11.)
Update
Поведение конструктора перемещения по умолчанию такое же, как конструктор копирования, правильно ли оно? Если это правда,
- Мы всегда ожидаем перемещения ctor, чтобы украсть ресурсы перемещенного объекта, в то время как по умолчанию он не ведет себя так, как ожидалось, так что точка, связанная с перемещением по умолчанию?
- Как узнать, имеет ли класс специальный конструктор перемещения (который может быть гарантированно корректно вести себя)?
Кажется, что foo f2(std::move(f));
вызывает копию ctor, когда я ее объявлял, см.
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;
}
Теперь вывод:
1
copy constructed
Если foo
имеет конструктор перемещения, то не будет foo f2(std::move(f))
называть его?
Итак, теперь мои вопросы: Как узнать, имеет ли класс перемещение ctor, и имеет ли он его, как я могу его явно вызвать?
То, что я пытаюсь сделать, это...
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);
}
Итак, я думал, что std::is_move_constructible<T>::value
может быть передан шаблону, а теперь я вижу, что этот признак заботится только о том, является ли T t(T())
допустимым выражением, он может вызвать T::T(const T&)
.
Предположим, что T
- это пользовательский класс, тогда я хочу, чтобы приведенные выше шаблоны действовали так:
- Если я не объявляю перемещение ctor, я хочу, чтобы этот метод шаблона вызывал
MoveAux<T,false>::doMove
. - Если я объявил один, мне нужно, чтобы он вызывал
MoveAux<T,true>::doMove
.
Можно ли выполнить эту работу?