[C++]尚方宝剑之右值引用
总结(有一个传说,总结放在文章开头,可以…)
C++11标准之前存在两个问题:
1.生成临时对象时耗时地copy操作
2.模板函数不能按照参数实际类型转发
C++11标准提出右值引用,作用如下:
1.语义转移
2.完美转发
从swap函数的四种实现聊到语义转移,上代码:
/**
* Desc: compare different swap functions including passing values directly,pointer,reference,rvalue reference
* Author: zhpmatrix
* Date: 2016-10-06 09:25
* Comments: My own swap function with tag showing 'z'
*/
template <typename T>
void zSwap_1(T a,T b){
T tmp;
tmp = a;
a = b;
b = tmp;
}
传值方式,由于存在临时对象的copy操作(copy了实参值),交换了临时对象的值,并未交换实参的值。
template <typename T>
void zSwap_2(T* a,T* b){
T tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
指针(传址)方式,由于存在临时对象的copy操作(copy了实参地址),交换了实参的值。
template <typename T>
void zSwap_3(T& a,T& b){
T tmp;
tmp = a;
a = b;
b = tmp;
}
引用方式,给实参取别名,交换了实参的值(本质上和指针方式类似)。
template <typename T>
void zSwap_4(T& a, T& b){
/* Move a to tmp and clear the space of a */
T tmp(move(a));
a = move(b);
b = move(tmp);
}
右值引用方式,”不copy,直接移动实参值!”
语义转移利用右值引用,结合关键字move,避免了临时对象的产生,也就避免了赋值构造函数和析构函数的调用,从而减小了函数调用开销,提高程序的运行效率。此外,还可用在增加右值生存期上等。
关于完美转发,上代码:
template<typename T>
void processValue(T& val){ cout << "lvalue:" << val << endl; }
template<typename T>
void processValue(T&& val){ cout << "rvalue:" << val << endl; }
template <typename T>
void forwardValue(T&& val){
processValue(std::forward<T>(val));
}
void test(){
float i = 0.6;
forwardValue(i);
forwardValue(0.6);
}
由上述代码可知,根据传入的类型,左右值类型,利用右值引用,结合关键字forward可以实现精确转发。
在STL中,有一个数据结构pair,表示数据对,在头文件utility中包含。其声明是:
template <class T1,class T2>
pair<V1,V2> make_pair(T1&& x,T2&& y);
下面是clang在编译时执行的模板实现:
return pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
下面是C++官网给出的实现:
pair<V1,V2>(std::forward<T1>(x),std::forward<T2>(y))
从源码中可以看到,支持完美转发。