C++中的引用

引用的注意事项

一、引用的「必守规则」(编译层面)

1、引用必须在定义时初始化

引用是变量的 "别名",不能先定义、后绑定,这是和指针最核心的区别。

cpp 复制代码
int a = 10;
int& ref1 = a;  // ✅ 正确:定义即绑定
// int& ref2;    ❌ 错误:引用未初始化(编译报错)

2、引用一旦绑定,无法更换绑定对象

引用的绑定关系是 "终身制",看似 "重新赋值" 的操作,实际是给原绑定变量赋值:

cpp 复制代码
int a = 10, b = 20;
int& ref = a;
ref = b;        // 不是绑定b,而是把b的值赋给a(a=20)
cout << a;      // 输出20,ref仍指向a

3、无 "空引用"、无 "引用的引用"、无 "指向引用的指针"

引用必须绑定有效变量,不存在nullptr引用;

引用本身不占独立内存,因此无法对引用再取引用,也不能定义指向引用的指针:

cpp 复制代码
int a = 10;
int& ref = a;
// int&& ref_ref = ref; ❌ 错误:无"引用的引用"(C++11右值引用≠引用的引用)
// int&* p = &ref;      ❌ 错误:无"指向引用的指针"
int* p = &ref;         // ✅ 正确:取引用地址=取原变量地址

二、引用的「生命周期陷阱」(运行层面)

1、禁止返回局部变量的引用

函数内局部变量存储在栈上,函数结束后立即销毁,返回其引用会产生 "悬空引用":

cpp 复制代码
// ❌ 错误示例
int& bad_func() {
    int temp = 50;
    return temp; // 局部变量销毁后,引用悬空
}
// ✅ 正确方案:返回静态变量引用(全局区,生命周期同程序)
int& good_func() {
    static int temp = 50;
    return temp;
}

2、左值引用避免绑定临时对象

普通左值引用(T&)不能绑定临时值(如函数返回值、表达式结果);

const左值引用(const T&)是例外,可延长临时对象的生命周期:

cpp 复制代码
int get_num() { return 100; } // 返回临时变量
// int& ref = get_num(); ❌ 错误:左值引用绑定临时值
const int& ref = get_num();  ✅ 正确:const引用延长临时变量生命周期

三、引用的「场景化注意事项」(实用层面)

cpp 复制代码
void modify(int& x) { x += 10; }
void print(const int& x) { cout << x; }
modify(10);  // ❌ 错误:非const引用不能绑字面量
print(10);   // ✅ 正确:const引用支持字面量

引用做函数参数

一、引用做函数参数的核心优势

相比传统的「值传递」,引用传参有两个关键优势:

1、避免拷贝:尤其是大对象(如自定义类、数组),值传递会复制整个对象,引用仅传递别名,大幅节省内存、提升效率;

2、可修改实参:通过非 const 引用可直接修改函数外部的实参,无需通过返回值传递修改结果。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 值传递:拷贝整个string(大对象,效率低)
void change_str_by_value(string s) {
    s = "hello value";
}

// 引用传递:无拷贝,可修改实参
void change_str_by_ref(string& s) {
    s = "hello reference";
}

int main() {
    string str = "original";
    change_str_by_value(str);
    cout << str << endl; // 输出:original(值传递不修改实参)
    
    change_str_by_ref(str);
    cout << str << endl; // 输出:hello reference(引用传递修改实参)
    return 0;
}

二、引用做函数参数的分类与使用场景

根据是否加const,引用参数分为两类,适用场景完全不同:

  1. 非 const 引用(T&)
    核心用途:需要修改函数外部的实参;
    限制:只能接收「左值」(即有名字的变量),不能接收字面量、表达式结果、临时对象;
cpp 复制代码
// 非const引用传参:修改实参
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 10, y = 20;
    swap(x, y); // ✅ 正确:传入左值(变量)
    cout << x << "," << y << endl; // 输出:20,10
    
    // swap(10, 20); ❌ 错误:非const引用不能绑定字面量(右值)
    // swap(x+5, y); ❌ 错误:非const引用不能绑定表达式结果(临时值)
    return 0;
}
  1. const 引用(const T&)
    核心用途:只读访问实参、避免大对象拷贝(最常用!);
    优势:可接收「左值」「右值」(字面量、表达式、临时对象),是 "万能传参方式";
    示例:打印大对象(避免拷贝)
cpp 复制代码
// 自定义大对象(示例)
struct BigObject {
    int data[10000]; // 大数组,拷贝成本高
    int id;
};

// const引用传参:只读、无拷贝
void print_big_obj(const BigObject& obj) {
    cout << "Object ID: " << obj.id << endl;
    // obj.id = 100; ❌ 错误:const引用禁止修改实参
}

int main() {
    BigObject obj{ {}, 123 };
    print_big_obj(obj); // ✅ 正确:传入左值
    
    // 临时构造对象(右值),const引用可接收
    print_big_obj(BigObject{ {}, 456 }); // ✅ 正确:传入临时对象
    return 0;
}
相关推荐
程序员阿鹏2 小时前
事务与 ACID 及失效场景
java·开发语言·数据库
趁月色小酌***2 小时前
JAVA 知识点总结2
java·开发语言
m5655bj2 小时前
C# 在 PDF 文档中添加电子签名
开发语言·pdf·c#
LinHenrY12272 小时前
初识C语言(预处理详解)
c语言·开发语言
Larry_Yanan2 小时前
Qt多进程(四)QTcpSocket
开发语言·c++·qt·ui
hqwest3 小时前
码上通QT实战02--登录设计
开发语言·qt·登录·ui设计·qt控件·qt布局·qt登录
superman超哥3 小时前
仓颉Actor模型的实现机制深度解析
开发语言·后端·python·c#·仓颉
superman超哥3 小时前
仓颉内存管理深度探索:引用计数的实现原理与实战
c语言·开发语言·c++·python·仓颉
资生算法程序员_畅想家_剑魔3 小时前
Java常见技术分享-13-多线程安全-锁机制-底层核心实现机制
java·开发语言