博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Google C++ Coding Style:右值引用(Rvalue Reference)
阅读量:6438 次
发布时间:2019-06-23

本文共 3845 字,大约阅读时间需要 12 分钟。

右值引用是一个C++11特性,标记为T&&。GSG中定义:只为移动建构函数(Move constructor)和移动赋值操作(Move assignment)使用右值引用。并且不要使用std::Forward(提供的完美转发特性)。

C++中右值指表达式结束时就不再存的临时对象。在C++11中,右值分为纯右值(即原始字面量,表达式产生的临时变量等),以及一个将亡值(expiring value, 使用<<深入应用C++11>>中的译法,指的是与右值引用相关的表达式,如将被移动的对象,T&&函数返回值等)。

以函数返回值表达不出右值引用的威力,因为编译的本身的优化会解决不必要的对象复制操作。而作为函数参数,如果使用const T&之类的形式也能够有效避免不必要的对象拷贝。这里特别以与标准容器配合,体现一下,右值引用最大的价值:避免深拷贝。

// 下面一个完整提供了Move Constructor和Move assignment的类。#include 
#include
#include
#include
class Foo { private: int x = 0; int y = 0; char* strPtr = nullptr; public: Foo() { std::cout << "Constructor was called." << std::endl; } Foo(const char* s) { std::cout << "Constructor with string:" << s << std::endl; if (s != nullptr) { strPtr = new char[strlen(s)]; strcpy(strPtr, s); } } // Copy constructor Foo(const Foo& a) : x(a.x), y(a.y) { // Deep copy copyStringValue(a.strPtr); std::cout << "Copy constructor was called." << std::endl; } // Move constructor, no need copy string in deep. Foo(Foo&& a) : x(a.x), y(a.y), strPtr(a.strPtr) { a.strPtr = nullptr; // 注意要清掉之前的字串,这样才是移动。 std::cout << "Move constructor was called." << std::endl; } Foo& operator=(const Foo& a) { x = a.x; y = a.y; copyStringValue(a.strPtr); std::cout << "Assignment Operator was called." << std::endl; } ~Foo() { if (strPtr != nullptr) { std::cout << "Free allocated string:" << strPtr << std::endl; delete strPtr; } std:: cout << "Deconstructor was called." << std::endl; } private: void copyStringValue(const char* s) { if (strPtr != nullptr) { delete strPtr; strPtr = nullptr; } if (s != nullptr) { strPtr = new char[strlen(s)]; strcpy(strPtr, s); } }};int main(void) { { std::cout << "Need to clear string twice:" << std::endl; std::vector
myVec; Foo a("Instance A"); myVec.push_back(a); } std::cout << "============" << std::endl; { std::cout << "Only need to clear string one time:" << std::endl; std::vector
myVec; Foo c("Instance C"); myVec.push_back(std::move(c)); } std::cout << "============" << std::endl; { Foo d("Instance D"); Foo x = d; } std::cout << "============" << std::endl; { Foo e("Instance E"); Foo&& y = std::move(e); }}

观察代码删除字串的次数,就可以了解右值引用的作用了。程序运行的输出如下:

Need to clear string twice:Constructor with string:Instance ACopy constructor was called.Free allocated string:Instance ADeconstructor was called.Free allocated string:Instance ADeconstructor was called.============Only need to clear string one time:Constructor with string:Instance CMove constructor was called.Deconstructor was called.Free allocated string:Instance CDeconstructor was called.============Constructor with string:Instance DCopy constructor was called.Free allocated string:Instance DDeconstructor was called.Free allocated string:Instance DDeconstructor was called.============Constructor with string:Instance EFree allocated string:Instance EDeconstructor was called.

但是考虑到右值引用中的引用折叠(reference collapsing)会引入一些复杂度(左右值的转换规则),造成理解上的问题,所以将右值引用的应用范围做了如开篇所说的限定。

在实际应用中,会出现没有直接定义类型的右值引用,被称为universal reference,需要进行类型推导。另一种情况是使用auto &&定义的也是universal reference。

关于std::forward,它被称为完美转发(Perfect Forwarding)。要解决的问题是在函数模板中,完全依照模板的参数的类型,保持参数的左值,右值特征),将参数传递给函数模板中调用的另一个函数(转自<<深入应用C++11>>)。根据这个定义,完美转发仅针对需要调用内部实现的模板函数,而且需要开发者识别出哪些情况是有效的,而哪些情况下又是无效的。比如适用的场景:

template
void foo(T&& arg) { // 如下保持arg的类型传入到bar()中 bar(std::forward
(arg));}

但如果内部函数无需要针对左值或右值做特殊处理,这种场景是不需要转发的。参考:。

转载地址:http://vfuwo.baihongyu.com/

你可能感兴趣的文章
在 SQL Server 中查询EXCEL 表中的数据遇到的各种问题
查看>>
linux sed命令
查看>>
浅谈当下网页设计趋势
查看>>
TCP 滑动窗口和 拥塞窗口
查看>>
VS2008调试程序时出现"XXX mutex not created."
查看>>
解决Java连接MySQL存储过程返回参数值为乱码问题
查看>>
c++ 字符检测 TCharacter
查看>>
MalformedObjectNameException: Invalid character '' in value part of property
查看>>
Hadoop格式化HDFS报错java.net.UnknownHostException: localhost.localdomain: localhost.localdomain
查看>>
android 40 Io编程
查看>>
编译器错误消息: CS0234: 命名空间“Purple”中不存在类型或命名空间名称“Model”(是否缺少程序集引用?)...
查看>>
天津政府应急系统之GIS一张图(arcgis api for flex)讲解(五)地图切换以及图层显示模块...
查看>>
STL之Vector(不定长数组)
查看>>
Python下科学计算包numpy和SciPy的安装【原创】
查看>>
I.MX6 android 设置 默认 动态桌面
查看>>
工作流数据库表设计-ASP.NET
查看>>
了解这23种设计模式
查看>>
linux程序调试命令strace
查看>>
代码中使用StoryBoard和DoubleAnimation的方法
查看>>
数据结构 线性表链式队列
查看>>