左值引用与右值引用

C++里面除了普通的左值引用(string&)以外,还有右值引用(如string&&),以及引用折叠。右值引用主要是为了开发人员作为一个C++库的开发者,可以配合编译器更有效地优化代码而发明,我们来看下面这么一个例子:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

vector<int> MakeVector(int startP, int endP) {
	vector<int> numbers;
	for (int i = startP; i <= endP; i++) {
		numbers.push_back(i);
	}
	return numbers;
}

class Sum {
private:
	vector<int> numbers;

public:
	explicit Sum(const vector<int>& theNumbers):numbers{theNumbers}
	{}
	
	int Get() {
		int sum = 0;
		for (auto &i : numbers) {
			sum += i;
		}
		return sum;
	}
};



int main() {

	Sum sum{ MakeVector(3, 7) };
	cout << sum.Get() << endl;


	system("PAUSE");
	return 0;

通过visual studio的断点操作我们可以发现,这里会三次调用vector构造函数操作:

Vector::vector():发生在MakeVector里面构造numbers的时候

Vector::vector(vector&&):发生在makevector里面return的时候

Vector::vector(const vector<int>& theNumbers):numbers{theNumbers}

这第二次调用return的时候就是右值引用

右值引用其实说的就是已经再也不需要被用到的对象的引用,譬如makeVector里面,

Return numbers里面的numbers.在return了之后,这个变量已经没有用了,所以会使用右值引用复制构造函数

那这个构造函数有什么不同之处呢?我们可以想象里面维护了一个指向数组的指针,而复制vector实际上就是要构造一个新的数组,然后把复制的值都拿过去,但我们知道正在被复制的vector已经在别的地方用不到了,那我们可以把它的指针直接拿过来用

我们只需把指针传过去后,自己这边设置为空指针即可

右值引用是十分有好处的,可以节省很多复制对象的开销,调用右值引用的复制构造函数,我们可以认为对象直接跑过去了,并没有发生任何复制

我们来看之前string例子中的一些操作:

String& operator=(String&& theString)
    {
        if (this != &theString)
        {
            delete[] buffer;
            length = theString.length;
            buffer = theString.buffer;
            theString.buffer = nullptr;
        }
        return *this;
}

String(String&& theString):length{theString.length},buffer{ theString.buffer}
    {
        theString.buffer = nullptr;
    }

这是一个复制构造函数和赋值号的重载操作,使用了右值引用传递法,这时候和链表一样,只需把指针覆过去并进行空指针操作即可

不需要像左值引用一样调用相关接口进行操作

折叠:

#include <iostream>

using namespace std;

void Print(int& x)
{
    cout << "x is int&" << endl;
}

void Print(int&& x)
{
    cout << "x is int&&" << endl;
}

template<typename T>
void CallPrint(T&& x)
{
    Print(x);
}

int main()
{
    int x = 0;
    CallPrint(x);
    CallPrint(0);
    return 0;
}

因为CallPrint(0)里面的0是右值,而callPrint的参数x类型是T&&,那么T只能是int->参数X的类型是int&&。但是尽管如此,这里的参数x已经有一个名字了C++语法并不阻止我们在print(X)后继续使用x,所以是左值引用

猜你喜欢

转载自blog.csdn.net/alex1997222/article/details/81225494
今日推荐