C++ 11的右值引用

C++一直号称是比C在类型上更安全的语言,比如C++中可以使用引用(typereference)来在很大范围内代替指针的使用。引用的安全性来自于它的使用受到了编译器的严格控制,必须与一个有址可循的值绑定才可以。所以传统上C++的引用是左值引用(lvalue reference),然而C++11中右值应用(rvalue reference)也被引入成为一个新的语言特性。

 

让我们先搞清一个概念,什么是左值和右值。请看下面这个表达式:

		int a;
		a = 1+1;
	

其中等号左边的a就是左值(lvalue),而等号右边1+1产生了一个为2的右值(rvalue)。两者的区别是在这个表达式执行后,a还可以被访问,而产生了的这个右值2的有效范围却在这个表达式之内,是一个临时的值。

传统上C++的引用是一个左值引用:

		int a = 1;
		int& lvalueref1 = a;
		int& lvalueref2= 2; // 错误,因为2是一个右值
	

C++11中引入了右值引用:

		int a = 1;
		int&& rvalueref1 = 2;
		int&& ravlueref2 = a; // 错误,右值引用只能绑定到右值
	

有一点需要注意的就是,不管左值引用还是右值引用,都可以作为一个左值来使用:

		int a = 1;
		int& b = a;
		b = 2; //左值引用作左值
		int&& c = 2;
		c = 3; // 右值引用作左值
	

但是问题来了,右值引用到底能干什么呢?要知道创建右值引用是为了和左值引用相区别,所以右值引用最大的用处也在于如此。举个例子:

		#include <iostream>
		#include <string>
		using namespace std;
		 
		void printString(string str)
		{
		  cout << str;
		}
	

printString接受所有string类型的值,包括左值和右值。但是每次调用printString时,这个值都会被拷贝一次,效率比较低。通常的改进方式是选择传引用的方式来传值,例如:

		void printString(string& str);
	

但是这种声明无法接受一个右值为参数,例如printString(“ABC”);就被编译器视为不合法。进一步的改进是以const引用的方式传递参数:

		void printString(conststring& str);
	

这样避免了函数调用时的参数拷贝,但是因为是const引用,除非强制转化,在printString函数内部无法修改str的值。引入右值引用之后,就有一个两全其美的办法了,首先重载printString:

		void printString(const string& str)
		{
		  cout << str;
		}
		 
		void printString(string&& str)
		{
		  cout << str;
		}

这样,对于入参是右值的时候,例如printString(“ABC”)时,printString(string&& str)的版本会被调用。

更美好的是,我们可以将一个左值伪装成右值,让编译主动选择printString(string&&str)的版本。例如,我们定义了一个string类型的变量hello,明显hello是一个左值,所以printString(hello)肯定调用的是printString(const string& str)。假如我们将hello伪装成一个右值,那么不就可以让编译器选择调用printString(string&& str)了吗!

标准库中提供了一个函数std::move来干这事,std::move将一个左值伪装成一个右值。printString(std::move(hello))时,我们就成功了选择了printString(string&& str)这个版本。

这样做有何意义呢?试想,如果printString不是一个普通函数,而是一个类的构造函数:

		class X {
		  X(const X&);
		  X(X&&);
		};
	

C++11之前我们只有拷贝构造函数X(constX&),这个函数通过拷贝X对象的一个实例来创建一个新的实例。C++11中,我们有了X(X&&),暂且翻译成传递构造函数(moveconstructor),这个函数不仅可以用一个既有实例创建一个新实例,还可以修改既有实例的内容!现在我们可以创建一种类型,这种类型的实例不可以被拷贝,但是它的内容却可以被传递。例如C++11中的fstream,由于包含文件句柄,不可以拷贝,但现在fstream可以把文件句柄转给另外一个实例了。

参考连接:

·      http://www.stroustrup.com/C++11FAQ.html#rval

·      http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值