通过左值引用传参

背景:值传递的代价

在 《函数形参与实参简介》中,我们介绍了值传递(pass by value):实参被拷贝到形参。

#include <iostream>
void printValue(int y) { std::cout << y << '\n'; }

int main() {
    int x{ 2 };
    printValue(x);   // x 被拷贝到 y
}

对基本类型而言,拷贝成本极低;但对标准库中的类类型(如 std::string)则往往昂贵:

#include <iostream>
#include <string>
void printValue(std::string y) { std::cout << y << '\n'; }

int main() {
    std::string x{ "Hello, world!" };
    printValue(x);   // 每次调用都拷贝一个 std::string
}

为避免不必要的昂贵拷贝,我们采用引用传递(pass by reference)

引用传递

将形参声明为引用类型(或常量引用类型)。调用时,引用形参直接绑定到实参,无需拷贝:

#include <iostream>
#include <string>
void printValue(std::string& y) { std::cout << y << '\n'; }

int main() {
    std::string x{ "Hello, world!" };
    printValue(x);   // y 绑定到 x,无拷贝
}

关键要点
引用传递让我们在不拷贝实参的情况下把数据传入函数。

证明:引用即别名

#include <iostream>
void printAddresses(int val, int& ref) {
    std::cout << "值形参地址: " << &val << '\n';
    std::cout << "引用形参地址: " << &ref << '\n';
}

int main() {
    int x{ 5 };
    std::cout << "x 地址:       " << &x << '\n';
    printAddresses(x, x);
}

输出示例:

x 地址:       0x7ffd16574de0
值形参地址: 0x7ffd16574de4
引用形参地址: 0x7ffd16574de0
  • 值形参与 x 地址不同,说明是独立对象。
  • 引用形参与 x 地址相同,证明引用即别名。

通过引用修改实参

值传递时,函数内对形参的修改不影响实参:

#include <iostream>
void addOne(int y) { ++y; }   // 修改的是拷贝

int main() {
    int x{ 5 };
    addOne(x);
    std::cout << x; // 5
}

引用传递时,对形参的修改直接作用于实参:

#include <iostream>
void addOne(int& y) { ++y; }  // 修改原对象

int main() {
    int x{ 5 };
    addOne(x);
    std::cout << x; // 6
}

关键要点
非常量左值引用允许函数修改实参,可用于“在函数内更新外部对象”的场景。

非常量左值引用的限制

非常量左值引用只能绑定到可修改的左值,因此:

#include <iostream>
void printValue(int& y) { std::cout << y << '\n'; }

int main() {
    int x{ 5 };
    printValue(x);   // OK

    const int z{ 5 };
    printValue(z);   // 错误:z 是 const

    printValue(5);   // 错误:5 是右值
}

下一课将介绍常量左值引用来解决此限制,并讨论何时用值传递、何时用引用传递。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"