C++ 0x之右值引用

C++ 0x标准出来有一段时间了,一直没时间看,导致最近看一些代码完全不明白是什么意思了,只好硬着头皮来看了。

这次先说一个简单的,右值引用。

关于引用,大家都很清楚了,只会做一标识,而不会拷贝对象,例如:int a = 0; int& b = a; 这个就是传统的引用,如今也称为左值引用,一般我们将引用用在函数返回值和参数传递上。现在0x标准出来了一个右值引用。为了区别左值引用,就变成右值引用了,用”&&“来表示。

左值引用和右值引用最大的却别是:右值引用可以绑定到一个临时的对象(右值)上,而左值引用不行

int a = 0;
	int& nLvRef = a;	// 左值引用

	int&& nRvRef = int();	// 右值引用

上面的是例子是一个左值引用和右值引用的例子。再看下面的例子:

int& nLvRef = int();	// 左值引用, VS报错:非常量引用的初始值必须是左值 error C2440: “初始化”: 无法从“int”转换为“int &”

	int&& nRvRef = int();	// 右值引用

从而可见,我们把一个临时对象(右值)绑定大了一个右值引用上,而左值引用却不可以这样绑定。

右值引用可以绑定一个临时(匿名)的对象,而临时的对象没有必要保存下来,进行操作的时候我么你可以”移动(Move)”它,而不是拷贝一个副本下来,这样就可以减少拷贝副本所带来的开销。

例如我们有下面的例子:

void swap(int& a , int& b)
{
	int temp = a;
	a = b;
	b = temp;
}

int _tmain(int argc, _TCHAR* argv[])
{

	int a = 1;
	int b = 2;
	swap(a, b);
	std::cout << a << "	" << b << std::endl;
	system("pause");
	return 0;
}

结果我们都很清楚,a和b的值交换了,但是这里大家注意到,用一个临时对象来做中间变量,我们做了很多次的对象拷贝。

下来我们使用右值引用中移动的思想来改写这个swap函数,如下:

void swap(int& a , int& b)
{
	int temp = std::move(a);
	a = std::move(b);
	b = std::move(temp);
}

int _tmain(int argc, _TCHAR* argv[])
{

	int a = 1;
	int b = 2;
	swap(a, b);
	std::cout << a << "	" << b << std::endl;
	system("pause");
	return 0;
}

这里你可能没看到右值引用操作符,但是却用了一个std::move(),这个是VS标准库中自带的一个移动函数。

我们来用右值引用模拟一下这个标准函数(稍微吐槽下,MS慢慢也接受了boost等公众认可的东西了,不搞特殊化了,以MS当年的性格,绝对要单独搞一个另外名字的函数)

template<typename T>
T&& move(T&& a)
{
	return a;
}

template<typename T>
void swap(T& a , T& b)
{
	int temp = move(a);	// a被移动到temp,a被清空
	a = move(b);		// b被移动到a,b被清空
	b = move(temp);		// temp被移动到a,temp被清空
}

int _tmain(int argc, _TCHAR* argv[])
{

	int a = 1;
	int b = 2;
	swap(a, b);
	std::cout << a << "	" << b << std::endl;
	system("pause");
	return 0;
}

注意:这里是移动,并没有做拷贝,只是将对象移动了一下而已,你可以认为是同一个你还了不同编号的座位。

C++0x中的右值引用算是将引用这块的东西补全了,虽然左值引用也很好用,但是大家对他的效率以及临时对象的处理上不是很满意,而右值引用完美的解决了这个问题。

不过现在大家用的VS编辑器各不一致,想要用右值引用需要VS2010(包含)以上的版本,建议还是用VS2012吧,2010的支持不全面。GCC最先的4.7.3已经全面支持C++ 0x标准了。还是喜欢GCC的果断,而不像VS一样拖泥带水,今天支持一点,sp1再支持一点,纠结。

好了,这个东西这么好用,有必要的话建议大家升级下项目

你可能感兴趣的:(C++ 0x之右值引用)