左值引用
左值引用
案例
swap 案例
看看下面的 C 语言实现的交换的错误代码:
#include <stdio.h>
#include <stdlib.h>
void swap(int _left, int _right) {
int temp = _left;
_left = _right;
_right = temp;
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
printf("%d\r\n%d", a, b);
return 0;
}
/**
10
20
*/
在将代码修改为指针方式后:
#include <stdio.h>
#include <stdlib.h>
void swap(int* _left, int *_right) {
int temp = *_left;
*_left = *_right;
*_right = temp;
}
int main() {
int a = 10;
int b = 20;
swap(&a, &b);
printf("%d\r\n%d", a, b);
return 0;
}
这个结果是我们需要的,两个变量的值成功交换了,第一段代码错误的原因是什么?在调用 swap 函数时,a,b 被拷贝了一份,在函数体里面,对 a,b 的操作实际上是对 a,b 副本的操作。第二种方法虽然达到了目的,但是总有麻烦和不美观。我们可以再修改为引用传参:
#include <iostream>
void swap(int& _left, int& _right) {
int temp = _left;
_left = _right;
_right = temp;
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
std::cout << a << std::endl << b << std::endl;
return 0;
}
可以看到,swap 函数只被改动了很小的一部分,但是结果有所不同,因为当 a,b 传入 swap 函数时,a,b 没有被拷贝,在函数体内对 a,b 的操作就是对它们本身进行操作。下面提供了一种 swap 函数的版本:
void swap(int& _left, int& _right) {
int temp = std::move(_left);
_left = std::move(_right);
_right = std::move(temp);
}
这是标准库实现 swap 的方法,通过右值引用减少不必要的内存大小
避免多次构造案例
#include <iostream>
class Student {
public:
Student(int _id = 0)
: id_(_id) {
std::cout << "Student()" << std::endl;
}
Student(Student& other)
: id_(other.id_) {
std::cout << "Student(Student&)" << std::endl;
}
Student(Student&& other)
: id_(other.id_) {
std::cout << "Student(Student&&)" << std::endl;
}
~Student() {
std::cout << "~Student()" << std::endl;
}
int id() {
return id_;
}
private:
int id_;
};
void printId(Student s) {
std::cout << s.id() << std::endl;
}
int main() {
Student s;
printId(s);
return 0;
}
/**
Student()
Student(Student&)
0
~Student()
~Student()
**/
在 main 函数中只有一个 Student 对象,为什么被析构了两次?再看看输出,有一个 Student(Student&),看来 s 是被拷贝过一份的,但是我们并不需要这种拷贝,拷贝了有什么效果吗,显然在这个程序中没有,所以我们应该使用引用传递参数而不是值传递参数
void printId(Student& s) {
std::cout << s.id() << std::endl;
}