MyType
定义了副本和移动ctor。执行以下代码段时(使用VS2015编译后):
template<typename T>
void f(T&& o) {
// do something with o
}
int main() {
MyType o{ 1, 2, 3 };
f(o); // call of copy-constructor expected
f(std::move(o)); // call of move-constructor expected
}
我希望在第二次调用f
之后第一次调用f
和移动构造函数之后调用复制构造函数。但是在任何情况下都没有构造函数被调用。我怀疑这种行为是编译器优化,但我不确定可移植性或符合标准。
两个调用都是引用 - 第一个是左值引用,第二个是和右值引用。 T&&
与两者合作,被称为forward reference(N4164)。 Scott Meyers称他们为universal references,特别适合作为模板参数和auto&&
。
std::move
用于表示所有权转移,但实际上并未采取任何行动。它的效果是static_cast到rvalue引用。
所以你有了:
void f(MyType& ) {}
void f(MyType&& ) {}
...
f(o); // calls void f(MyType& )
f(static_cast<MyType&&>(o)); // calls void f(MyType&& )
通常在初始化对象时调用移动构造函数。
Move constructors cppreference.com
每当通过重载决策选择时调用移动构造函数,这通常发生在从rvalue(xvalue或prvalue)(直到C ++ 17)xvalue(从C ++ 17开始)初始化对象(通过直接初始化或复制初始化)时(从C ++ 17开始) )相同类型,包括
- 初始化:
T a = std::move(b);
或T a(std::move(b));
,其中b是T类型;- 函数参数传递:
f(std::move(a));
,其中a是T类型,f是void f(T t);
- 函数return:
return a;
在T f()
之类的函数中,其中a是T类型,它有一个移动构造函数。
如果将f
更改为void f(T o)
,则将为第一次调用调用复制构造函数,为第二次调用调用移动构造函数。