是否 std::is_move_constructible<T>::value == true
暗示 T
有一个可用的 move 构造函数?
如果是这样,它的默认行为是什么?
考虑以下情况:
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
move 构造? - 如果是,右值不应该失效吗?
- 我如何知道类的实例是否可以正确 move 构造(使旧实例无效)?
(我正在使用 VS11。)
更新
move 构造函数的默认行为与复制构造函数相同,是否正确? 如果是真的,
- 我们总是希望 move ctor 窃取被 move 对象的资源,而默认 move ctor 的行为不如预期,那么拥有默认 move ctor 有什么意义?
- 我如何知道一个类是否有自定义 move 构造函数(可以保证其行为正常)?
看来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
有一个 move 构造函数,那么不会foo f2(std::move(f))
叫它?
所以现在我的问题是: 如何知道一个类是否有 move 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
是一个自定义类,那么我希望上面的模板表现得像:
- 如果我不声明 move ctor,我希望该模板方法调用
MoveAux<T,false>::doMove
. - 如果我声明了一个,我需要它调用
MoveAux<T,true>::doMove
.
有没有可能实现这个功能?
最佳答案
does
std::is_move_constructible<T>::value == true
implies thatT
has a usable move constructor?
move 构造函数或复制构造函数。请记住,复制构造的操作满足操作 move 构造的所有要求,甚至更多。
在标准术语中,MoveConstructible
对象是对其表达式求值的对象:
T u = rv;
使u
等价于构造前的rv
的值; rv
在被移出后的状态是未指定。但由于未指定,这意味着状态甚至可能与 rv
在 被 move 之前的状态相同:换句话说,u
可能是 rv
的拷贝。
事实上,标准将 CopyConstructible
概念定义为 MoveConstructible
概念的改进(因此 CopyConstructible
的所有内容也是 MoveConstructible
,但反之则不然)。
if so, what is the default behaviour of it?
隐式生成的 move 构造函数的行为是对生成它的类型的数据成员执行逐个成员 move 。
根据 C++11 标准的第 12.8/15 段:
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 ]
此外:
1 - is
f2
move constructed ?
是的。
2 - if so, shouldn't the rvalue be invalidated?
move 一个指针与复制它是一样的。所以没有失效发生,也不应该发生。如果您想要一个 move 构造函数,使 move 对象处于特定状态(即将指针数据成员设置为 nullptr
),您必须编写自己的 - 或将此责任委托(delegate)给某些智能指针类,例如 std::unique_ptr
。
注意,“invalidated”这个词在这里并不完全正确。 move 构造函数(以及 move 赋值运算符)旨在使 move 对象保持有效(但未指定)状态。
换句话说,需要尊重类不变量 - 并且应该可以调用对其状态没有任何先决条件的 move 对象操作(通常是销毁和赋值)。
关于c++ - 编译器生成的 move 构造函数的行为是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16055297/