C++ 现代C++编程艺术5-万能引用
文章目录
- [C++ 现代C++编程艺术5-万能引用](#C++ 现代C++编程艺术5-万能引用)
-
- [一、引用基础进阶 📚](#一、引用基础进阶 📚)
-
- [1. 常量引用(const lvalue reference)](#1. 常量引用(const lvalue reference))
- [2. 右值引用(rvalue reference)](#2. 右值引用(rvalue reference))
- [3. 引用作为返回值](#3. 引用作为返回值)
- 二、万能引用🔮
-
- [1. 核心定义](#1. 核心定义)
- [2. 运作原理(引用折叠)](#2. 运作原理(引用折叠))
- [3. 完美转发(Perfect Forwarding)](#3. 完美转发(Perfect Forwarding))
- [三、高级技巧组合应用 ⚙️](#三、高级技巧组合应用 ⚙️)
-
- [1. SFINAE + 引用控制](#1. SFINAE + 引用控制)
- [2. 引用限定成员函数](#2. 引用限定成员函数)
- [3. Lambda捕获引用陷阱](#3. Lambda捕获引用陷阱)
- [四、性能与安全性指南 🎯](#四、性能与安全性指南 🎯)
- [五、现代C++演进(C++20/23) 🌐](#五、现代C++演进(C++20/23) 🌐)
一、引用基础进阶 📚
1. 常量引用(const lvalue reference)
cpp
void process(const std::string& str) {
// 可接受:左值、右值、临时对象
// 保证不修改原始数据
}
特性:
- ✅ 可绑定左值/右值
- 🛡️ 防止意外修改
- ⚡ 避免拷贝开销(尤其大型对象)
2. 右值引用(rvalue reference)
cpp
void consume(std::string&& str) {
// 仅接受右值(临时对象)
// 可安全"窃取"资源(移动语义)
data_ = std::move(str);
}
应用场景:
- 🚀 实现移动构造函数/赋值运算符
- ⏱️ 高性能资源转移(如vector扩容)
3. 引用作为返回值
cpp
class Matrix {
double& operator()(int i, int j) {
return data_[i*cols_+j];
}
};
// 支持链式赋值:mat(2,3) = 1.5;
注意:
⚠️ 禁止返回局部变量的引用
二、万能引用🔮
1. 核心定义
cpp
template<typename T>
void magic(T&& param) { // "T&&" 是万能引用
// 根据传入实参自动推导:
// • 左值 → T 推导为 Type& (左值引用)
// • 右值 → T 推导为 Type (普通类型)
}
2. 运作原理(引用折叠)
传入实参类型 | T 推导结果 |
T&& 最终类型 |
---|---|---|
int (右值) |
int |
int&& |
int& (左值) |
int& |
int& |
int&& (右值) |
int |
int&& |
关键公式:
T&&
+ 左值引用 → 触发引用折叠 → 左值引用
3. 完美转发(Perfect Forwarding)
cpp
template<typename... Args>
auto make_wrapper(Args&&... args) {
return Wrapper(std::forward<Args>(args)...);
}
组件:
- 🧬
std::forward<Args>(args)
:保持值类别(左值/右值) - 📦 参数包
Args&&...
:支持任意数量参数
三、高级技巧组合应用 ⚙️
1. SFINAE + 引用控制
cpp
template<typename T>
auto process(T&& val) -> std::enable_if_t<
std::is_integral_v<std::decay_t<T>>, void
> {
// 仅接受整型(过滤引用/const修饰)
}
2. 引用限定成员函数
cpp
class Data {
void save() & { // 左值对象调用
std::cout << "保存到持久存储\n";
}
void save() && { // 右值对象调用
std::cout << "保存后立即销毁资源\n";
}
};
// 用法:
Data d;
d.save(); // 调用左值版本
Data().save(); // 调用右值版本
3. Lambda捕获引用陷阱
cpp
auto create_handlers() {
std::vector<Handler> handlers;
for(int i=0; i<10; ++i) {
// 错误:捕获局部引用i(悬空引用)
handlers.push_back([&](){ use(i); });
// 正确:值捕获当前状态
handlers.push_back([i](){ use(i); });
}
return handlers;
}
四、性能与安全性指南 🎯
-
引用使用黄金法则
场景 推荐方式 风险规避措施 只读访问大型对象 const T&
避免临时对象生命周期 函数内部修改参数 T&
前置空指针检查 资源转移 T&&
移动后置为 nullptr
模板参数转发 T&&
+forward
禁用不完全类型 -
典型错误案例
cpp// 陷阱1:返回临时对象引用 const std::string& get_name() { return "Alice"; // 临时对象销毁 → 悬空引用 } // 陷阱2:万能引用误用 template<typename T> void store(T&& data) { cache_ = data; // 左值→深拷贝,右值→错失移动机会 // 正确:cache_ = std::forward<T>(data); }
五、现代C++演进(C++20/23) 🌐
-
概念约束(Concepts)优化万能引用
cpptemplate<std::movable T> // 明确要求可移动类型 void transfer(T&& obj) { target_ = std::forward<T>(obj); }
-
Deducing
this
(C++23)cppclass Button { void click(this auto&& self) { // 自动推导调用者值类别 if constexpr (std::is_lvalue_reference_v<decltype(self)>) { log("左键点击"); } else { log("临时按钮触发"); } } };
-
引用技术💎
技术 关键语法 核心作用 应用频率 常量引用 const T&
安全只读访问 ⭐⭐⭐⭐⭐ 右值引用 T&&
资源移动/性能优化 ⭐⭐⭐⭐ 万能引用 T&&
(模板上下文)完美转发/类型推导 ⭐⭐⭐⭐ 引用折叠 typedef T& &
→T&
支撑万能引用机制 ⭐⭐ 引用限定成员函数 void func() &
区分左值/右值对象行为 ⭐⭐