C++ 右值引用与移动构造
问题提出
struct Base {
Base() {std::cout << "ctor" << std::endl;}
Base(const Base& b) {std::cout << "copy ctor" << std::endl;}
Base(Base&& b) {std::cout << "move ctor" << std::endl;}
~Base() {std::cout << "dtor" << std::endl;}
};
template<typename T>
Base default_test(T&& a) {
return Base(a);
}
int main() {
default_test(Base {});
return 0;
}
如上,定义一个类Base
,并实现构造函数,复制构造函数与移动构造函数。T&&
为引用折叠,根据main函数中default_test(Base {})
,形参a
是一个右值引用。那么在default_test
中利用a
构造一个Base
实例时,会调用哪一个构造函数呢?
事实上,其输出为
ctor
copy ctor
dtor
dtor
如何使其利用移动构造函数呢?
使用static_cast或者std::forward
#include <iostream>
struct Base {
Base() {std::cout << "ctor" << std::endl;}
Base(const Base& b) {std::cout << "copy ctor" << std::endl;}
Base(Base&& b) {std::cout << "move ctor" << std::endl;}
~Base() {std::cout << "dtor" << std::endl;}
};
template<typename T>
Base default_test(T&& a) {
// Although the input is rvalue reference, but use `copy` not `move`
return Base(a);
}
template<typename T>
Base cast_test(T&& a) {
return Base(static_cast<Base&&>(a));
}
template<typename T>
Base forward_test(T&& a) {
return Base(std::forward<Base>(a));
}
int main() {
std::cout << "First, we do nothing!\n";
default_test(Base {});
std::cout << "Second, we cast the input argument!\n";
cast_test(Base {});
std::cout << "Finally, use std::forward!\n";
forward_test(Base {});
return 0;
}
输出如下:
First, we do nothing!
ctor
copy ctor
dtor
dtor
Second, we cast the input argument!
ctor
move ctor
dtor
dtor
Finally, use std::forward!
ctor
move ctor
dtor
dtor
可见在使用static_cast或者std::forward之后,可以成功调用move ctor
而非copy ctor
。
小结
能够完美的保留输入参数的左右值引用,便是std::forward
的一大用处。如上例,虽然输入参数为右值引用,但是右值引用本身在函数体中是可以取地址的,并不是一个右值。所以需要static_cast
或者std::move
或者std::forward
,但需要注意的是,前两者是强转为右值引用或者使用了移动语义。
环境
使用编译器下载链接提供的GCC 12.2.0
。