C++11中的右值引用

C++11中新的标准比较多,牵扯到的概念也比较多,有些一开始听上去好玄乎,但是了解了它的产生是有道理的后就能比较好的理解了。

首先,右值引用这个概念感觉很难理解,它和引用有啥关系呢?其实和引用一样,只是有点儿差异:右值引用它是引用了一个临时变量的(大部分情况下),当然你也可以把某个对象变成右值引用。

右值引用是为了解决深拷贝带来的消耗问题的。大家都知道,一个对象拷贝给另一个对象的时候,C++基本都是深拷贝,因为对象内牵扯到了指针成员的时候,浅拷贝会牵扯到指针重复释放而造成crash的问题。这些都是基础,当我们写了以下的函数的时候:

std::vector<int> GetVectorData()
{
    return std::vector<int>(1, 10);
}

void TestDeepCopy()
{
    std::vector<int> vec = GetVectorData();
}

这时候在GetVectorData函数中会返回一个vector临时变量,然后将它作为vec的复制构造函数的参数,复制构造函数会进行一次深拷贝,拷贝完成后,临时变量被析构,vec初始化完毕。

由上述的流程来看,其实消耗还是很大的。在这儿其实还是有优化空间的,就是将临时变量的资源,复制给vec,然后清除临时变量的资源引用,右值引用就是用来干这个事情的。

在C++11标准中,stl很多容器都有特殊的拷贝构造函数和=操作符函数,和普通的拷贝构造函数和赋值操作符的区别就是参数是一个右值引用

T&& ref

对,右值引用只是两个&&号而已,当该右值引用作为参数传递给了上述重载的函数后,那么就会进行资源转义,也就是将资源拷贝到本对象,并将右值引用对象的资源清空,那么这要就可以避免一次拷贝构造了,然后右值引用对象析构的时候,也会因为没有资源而不会实际进行析构,不会造成重复释放的问题。

在C++11中,上述的代码中GetVectorData返回的临时变量会自动转换为右值引用,从而调用vec的以右值引用为参数的拷贝构造函数,并进行资源转移,这样的话,就可以少一次深拷贝的过程,性能得到提升。

同时,我们也可以通过 std::move 函数将普通的变量转换为右值引用,将该右值引用传递给新的对象的时候,必须要注意传递后,变成右值引用的对象的资源会被清空,不要重复使用。

void TestRightReference()
{
    std::vector<int> tmp(2, 10);
    // tmp will be empty, and cpy has the resource of tmp
    std::vector<int> cpy = std::move(tmp);
}
共 2 条回复
  
[email protected]   (游客) 2021-10-10 08:30
作为开发 我只关心是否拷贝 实际是什么性质的值 我不关心 我感觉可以自己封装一层copy nocopy伪关键字 不再用左右值的概念
  
[email protected]   (游客) 2021-10-10 08:31
我觉得右值引用应该仅限于string类或持有实际string数据的类使用 因为string的本质是交互 是给人看的 最早的数据基本都来源于数值转换或静态配置 也就在数值转换并返回临时对象时 变为了右值 此时一般确实不宜返回指针 但移动不移动其实没什么意义 目的只是消除拷贝 而数值类数据 不给人看...
发表新回复

作者

sryan
today is a good day