C++的复合类型包含数组、结构体、类等,在使用这些复合类型作为函数参数时,指针传递和引用传递是比值传递更高效的选择,能够避免大对象拷贝带来的性能损耗。

指针传递的核心技巧
复合类型指针的声明与传递
传递复合类型指针时,需要先明确指针指向的类型,结构体指针可以通过箭头运算符访问成员,数组指针需要配合步长使用。
#include <iostream>
#include <cstring>
// 定义结构体复合类型
struct Student {
char name[20];
int age;
};
// 结构体指针传递函数
void update_student(Student* stu, const char* new_name, int new_age) {
if (stu == nullptr) { // 指针传递必须做空指针校验
return;
}
strcpy(stu->name, new_name);
stu->age = new_age;
}
int main() {
Student stu = {"张三", 18};
update_student(&stu, "李四", 20);
std::cout << "姓名:" << stu.name << ",年龄:" << stu.age << std::endl;
return 0;
}
指针传递的注意事项
- 所有指针参数入参前必须校验是否为
nullptr,避免空指针解引用崩溃 - 如果不需要修改指针指向的内容,建议声明为
const指针,提升代码安全性 - 数组作为指针传递时会退化为首元素指针,需要额外传递数组长度参数
引用传递的核心技巧
复合类型引用的使用规则
引用是变量的别名,必须在声明时初始化,且之后不能绑定到其他变量,传递复合类型引用时不需要额外取地址,使用方式和普通变量一致。
#include <iostream>
#include <vector>
// 类复合类型,使用引用传递避免拷贝
class DataContainer {
public:
std::vector<int> data;
void add(int val) {
data.push_back(val);
}
};
// 引用传递函数,修改容器内容
void add_data_to_container(DataContainer& container, int val) {
container.add(val);
}
int main() {
DataContainer container;
add_data_to_container(container, 10);
add_data_to_container(container, 20);
std::cout << "容器元素个数:" << container.data.size() << std::endl;
return 0;
}
引用传递的优势与限制
- 引用传递不需要拷贝整个复合对象,性能优于值传递,语法也更简洁
- 引用不能指向空值,不需要做空校验,减少了冗余判断逻辑
- 如果不希望函数修改入参内容,需要声明为
const引用,比如const DataContainer& - 引用不能重新绑定,不适合需要动态切换指向对象的场景
指针和引用传递的选择场景
| 场景 | 推荐选择 | 原因 |
|---|---|---|
| 需要表达参数可选(可传空) | 指针传递 | 引用不能为空,无法表达可选参数的语义 |
| 参数无需修改且不需要为空 | const引用传递 | 语法简洁,无需拷贝,安全性高 |
| 需要函数内部修改参数指向 | 指针的指针或指针引用 | 引用本身不能重新绑定,无法通过引用修改原指针的指向 |
| 传递大对象或容器类复合类型 | 引用传递 | 避免大对象拷贝,性能更高 |
常见错误规避技巧
指针传递返回局部变量地址、引用绑定局部变量是C++中非常常见的错误,会导致悬垂指针或悬垂引用,访问时触发未定义行为。
如果需要返回函数内部的复合对象,建议直接返回值(现代编译器会做返回值优化),或者通过出参用指针或引用传递预分配的对象。
#include <iostream>
// 错误示例:返回局部变量的指针
// int* get_local_ptr() {
// int num = 10;
// return # // 局部变量销毁后指针指向无效内存
// }
// 正确示例:通过引用出参传递结果
void get_result(int& out_val) {
int local_val = 10;
out_val = local_val; // 把局部变量的值赋给出参引用
}
int main() {
int result = 0;
get_result(result);
std::cout << "结果:" << result << std::endl;
return 0;
}