C++ 中值传参和引用传参
了解C++中的值传参和引用传参,我们从下面两个不同参数形式的方法展开说说void func(std::vector<int> v)
与 void func(std::vector<int>& v)
的区别
这两个函数声明的主要区别在于参数传递方式:一个是按值传递,一个是按引用传递。以下是详细对比:
1. 按值传递 void func(std::vector<int> v)
1.1 特点
- 创建副本:调用函数时会创建整个vector的完整副本
- 不影响原vector:函数内对vector的修改不会影响调用者的原始数据
- 性能开销:对于大型vector,复制所有元素会带来显著性能开销
- 内存使用:需要额外内存存储副本
1.2 示例
void modifyCopy(std::vector<int> v) {v.push_back(100); // 只修改副本
}int main() {std::vector<int> nums = {1, 2, 3};modifyCopy(nums);// nums仍然是{1, 2, 3},未被修改
}
2. 按引用传递 void func(std::vector<int>& v)
2.1 特点
- 无副本创建:传递的是原vector的引用(别名),不复制数据
- 影响原vector:函数内对vector的修改会直接影响调用者的原始数据
- 高性能:无论vector多大,传递成本都极低(只是一个引用/指针的开销)
- 可能被修改:调用者需要意识到传入的数据可能被修改
2.2 示例
void modifyOriginal(std::vector<int>& v) {v.push_back(100); // 修改原始vector
}int main() {std::vector<int> nums = {1, 2, 3};modifyOriginal(nums);// nums现在是{1, 2, 3, 100}
}
3.关键区别对比表
特性 | 按值传递 func(vector<int> v) | 按引用传递 func(vector<int>& v) |
---|---|---|
数据复制 | 是(完整复制) | 否(仅传递引用) |
修改影响原数据 | 否 | 是 |
性能 | 低(大型vector开销大) | 高(恒定开销) |
内存使用 | 需要额外内存 | 不需要额外内存 |
const安全性 | 自动保护原数据 | 需要显式使用const保护 |
适用场景 | 需要独立副本时 | 避免复制或需要修改原数据时 |
4.进阶考虑
4.1 常量引用版本 void func(const std::vector<int>& v)
void readOnly(const std::vector<int>& v) {// 可以读取但不能修改vfor (int num : v) {cout << num << " ";}// v.push_back(10); // 错误:不能修改const引用
}
- 结合了按引用传递的高效性和按值传递的安全性
- 明确表示函数不会修改输入数据
- 是现代C++推荐的做法,除非确实需要修改或需要副本
4.2 移动语义(C++11及以上)
void takeOwnership(std::vector<int>&& v) {// 可以高效"窃取"v的内容std::vector<int> local = std::move(v);
}
- 用于表示函数将取得数据的所有权
- 避免复制,适合临时对象或明确要转移所有权的场景
5. 最佳实践建议
优先使用const引用:对于不需要修改的大型对象
void func(const std::vector<int>& v);
按值传递:
- 需要独立副本时
- 小型或基本类型(如int、float等)
- 明确要复制数据时
非const引用:
- 需要修改调用者的数据时
- 明确函数会修改输入时
右值引用:
- 实现移动语义时
- 处理临时对象或需要转移所有权时
选择哪种形式取决于函数的具体需求和对性能的考虑。