C++11新特性-----右值引用

先说说引用

C++中的引用可以理解为给一个变量起一个别名,就像我们都有自己的名字,同样也有很多人有自己的小名,外号等,就像张三的小名--二狗就是张三的一个引用,遇到张三无论是说嘿!张三!还是嘿!二狗!张三都可以知道有人在叫他的名字,这就引用

引用的特点

在说左值引用和右值引用的特点之前我们必须要时刻记清一个问题,无论是右值引用还是左值引用本质上都是引用类型,他们都具有引用的特点和作用,那就先说下引用的特点和作用。

特点:

  1. 引用必须在声明时被初始化,一旦初始化就不能改变它的指向。
  2. 引用本身不占用内存空间,他只是为已经存在的一个变量起了一个别名,因此使用时不需要进行额外的内存分配和复制。
  3. 引用可以作为函数的参数和返回值,可以避免拷贝大对象的开销(这里也是右值引用很大的作用之一),提高程序的效率。
  4. 引用可以简化代码,使得代码更加清晰易懂。

作用:

  1. 作为函数参数:引用可以作为函数的参数传递,可以避免函数对参数的拷贝,提高程序的效率。
  2. 作为函数返回值:引用可以作为函数的返回值,可以避免函数
  3. 返回大对象的拷贝,提高程序的效率。

  4. 简化代码:引用可以简化代码,使代码更加清晰和易读。

  5. 实现函数或运算符的重载:引用可以用于实现函数或运算符的重载,使代码更加灵活和可扩展。

  6. 引用作为对象的别名:引用可以作为对象的别名,可以用于修改对象的值,或者用于操作对象的成员。

右值引用

C++11引入了右值引用的概念,他是一种新的引用类型,用于引用临时对象。在我们了解右值引用之前我们最后还需要了解下右值的概念。

右值:

右值我们可以粗俗的理解为(只能)放在等号右边的值,即不能被取地址的临时对象或字面值常量。右值可以是基本数据类型也可以是对象,这里包括临时对象和函数返回值等。

右值具有以下特点:

  1. 右值是临时的:右值是在表达式中临时生成的,一旦表达式结束,就会被销毁。

  2. 右值不具备地址:右值没有具体的内存地址,因此不能被取地址。

  3. 右值可以在表达式中被移动:由于右值是临时的,因此可以在表达式中被移动,而不需要进行拷贝操作。

右值引用的作用

我们要了解右值引用首先要了解他出现的原因,而右值引用的出现,正是为了利用起来很难被正常使用的右值,避免空间的频繁创建与销毁,大大提高了程序的效率。我们可以看下下面这段代码的运行结果。

#include<iostream>
using namespace std;

class A
{
public:
	int a;
	A() {};
	A(int num):a(num) {};
	A test(A a)
	{
		a.a = 1;
		return a;
	}
	A test2(A&& a)
	{
		cout << "test2";
		return a;
	}
	~A()
	{
		cout << "销毁了一个A对象"<<endl;
	}


};
void main()
{
	A a;
	a.test(a);
	char c = getchar();
}

我们可以看到,当程序运行到getchar阻塞时,调用了两次析构函数,这里的两次就是函数传参和函数返回时发生的对象创建和销毁。

此时我们将这个程序修改为这样:

#include<iostream>
using namespace std;

class A
{
public:
	int a;
	A() {};
	A(int num):a(num) {};
	A test(A a)
	{
		a.a = 1;
		return a;
	}
	A test2(A&& a)
	{
		cout << "test2";
		return a;
	}
	~A()
	{
		cout << "销毁了一个A对象"<<endl;
	}


};
void main()
{
	A a;
	A && b = a.test(move(a));//move函数将a这个左值转化为右值
	char c = getchar();
}

 此时再次运行,我们就会发现函数在getchar()阻塞之前不会调用析构函数,也就是说没有新的对象被创建销毁。

这样我们就节省了两次对象的创建销毁,如果A这个类变得很大很大,那么右值引用就为我们节省下程序的很多开销。这就是右值引用很大的优点。

右值引用的特点和作用:

特点:

  1. 右值引用使用&&符号来声明,例如int&& x = 10;。

  2. 右值引用只能绑定到右值,不能绑定到左值。

  3. 右值引用可以被赋值和拷贝,但是被拷贝的对象的状态会被转移,即被拷贝的对象变成了空对象。

  4. 右值引用可以用于实现移动语义(move),即将一个对象的资源所有权从一个对象转移到另一个对象,避免了不必要的拷贝和销毁操作。

  5. 右值引用可以用于实现完美转发(forward),即将一个函数的参数转发给另一个函数,使得被转发的参数类型和值都能保持不变。

  6. 右值引用可以用于优化代码,例如在返回临时对象时,可以使用右值引用来避免不必要的拷贝操作,提高程序的效率。

作用:

  1. 实现移动语义:通过右值引用可以实现移动语义,避免了不必要的拷贝和销毁操作,提高程序的效率。

  2. 实现完美转发:通过右值引用可以实现完美转发,避免了参数类型和值的改变,提高程序的灵活性和可扩展性。

  3. 优化代码:通过右值引用可以避免不必要的拷贝操作,提高程序的效率。

  4. 实现函数或运算符的重载:右值引用可以用于实现函数或运算符的重载,使代码更加灵活和可扩展。

 move:

c++11添加了右值引用,却不能左值初始化右值引用,在一些特定的情况下免不了需要左值初始化右值引用(用左值调用移动构造),如果想要用左值初始化一个右值引用需要借助std::move()  函数。move() 函数可以将左值转换为右值。就像我上面演示的那样。

forward:

右值引用类型是独立于值的,一个右值引用作为函数参数的形参时,在函数内部转发该参数给内部其他函数时,他就变成了一个左值(当右值被命名是编译器会认为他是个左值),并不是原来的类型了。如果按照参数原来的类型转发到另一个函数,可以使用c++11的  std::forward()函数,该函数实现的功能称之为完美转发。

#include <iostream>
using namespace std;

template<typename T>
void printValue(T& t)
{
	cout << "左值引用: " << t << endl;
}

template<typename T>
void printValue(T&& t)
{
	cout << "右值引用:" << t << endl;
}

template<typename T>
void testForward(T&& v)
{
	printValue(forward<T>(v));
	cout << endl;
}

int main()
{
	testForward(520);//右值类型,转化为右值引用
	int num = 1314;
	testForward(num);//左值引用,转化为左值
	testForward(forward<int>(num));//forward将num转化为右值,再转发为右值
	testForward(forward<int&>(num));//forward将num转化为左值引用,再转发为左值
	testForward(forward<int&&>(num)); // forward将num转化为右值,再转发为右值
	return 0;
}

可以看到运行结果:

 此时这个testForward函数被称为完美转发函数。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值