面试题答案
一键面试- 性能差异
- 引用:
- 引用在本质上是一个“别名”,编译器在编译阶段会将引用替换为被引用对象的地址,在使用上它像对象本身一样直接操作,没有额外的间接寻址开销。
- 引用一旦初始化后不能再改变指向,在使用过程中编译器可以更好地进行优化,生成更紧凑的代码。
- 指针:
- 指针存储的是对象的地址,在访问指针所指向的对象时,需要通过间接寻址操作(解引用
*
运算符)来获取对象。这会带来一定的额外开销,尤其是在频繁解引用的情况下。 - 指针的值可以在运行时改变,指向不同的对象,这增加了程序的灵活性,但也使得编译器较难进行某些优化,因为它需要考虑指针指向的不确定性。
- 指针存储的是对象的地址,在访问指针所指向的对象时,需要通过间接寻址操作(解引用
- 引用:
- 差异明显的情况举例
- 循环中频繁访问对象:
- 使用引用:
- 循环中频繁访问对象:
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
int& ref = numbers[0];
for (size_t i = 0; i < numbers.size(); ++i) {
ref = numbers[i];
std::cout << ref << " ";
}
return 0;
}
在这个例子中,ref
作为 numbers[0]
的引用,在循环中直接访问和修改 numbers
中的元素,没有额外的间接寻址开销。
- 使用指针:
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
int* ptr = &numbers[0];
for (size_t i = 0; i < numbers.size(); ++i) {
*ptr = numbers[i];
std::cout << *ptr << " ";
ptr++;
}
return 0;
}
这里使用指针 ptr
,每次访问和修改元素都需要解引用操作 *ptr
,产生额外开销,尤其是在大数据量的循环中,这种开销会更加明显。
- 函数参数传递:
- 引用作为参数:
#include <iostream>
void modifyValue(int& value) {
value++;
}
int main() {
int num = 5;
modifyValue(num);
std::cout << num << std::endl;
return 0;
}
引用作为函数参数传递时,编译器可以直接对传入的对象进行操作,没有额外的地址传递开销。 - 指针作为参数:
#include <iostream>
void modifyValue(int* value) {
(*value)++;
}
int main() {
int num = 5;
modifyValue(&num);
std::cout << num << std::endl;
return 0;
}
指针作为参数传递时,需要先传递指针的值(即地址),在函数内部再通过解引用操作来访问和修改对象,相比引用多了间接寻址的过程,在频繁调用这种函数时性能差异会体现出来。