总结(有一个传说,总结放在文章开头,可以…)


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))

从源码中可以看到,支持完美转发。