1. 左值引用 vs 右值引用
左值引用
定义:给左值取别名,用&表示。
特点:
能获取地址,有持久状态
可出现在赋值符号左边或右边
主要作用是减少拷贝,提高效率
int a = 10; int& ref_a = a; // 左值引用 const int& const_ref = 20; // const左值引用可以绑定右值右值引用
定义:给右值取别名,用&&表示。
特点:
不能获取地址,通常是临时对象或字面量
只能出现在赋值符号右边
核心作用是实现移动语义,避免深拷贝
int&& rref = 10; // 字面量右值 int&& rref2 = std::move(a); // 将左值转为右值引用2. 右值引用的使用场景和效率提升
场景1:深拷贝类的移动构造/赋值
对于需要深拷贝的类(如string,vector),移动语义可以"窃取"资源而非拷贝:
class String { private: char* _str; size_t _size; public: // 移动构造函数 String(String&& s) noexcept : _str(s._str), _size(s._size) { s._str = nullptr; // 源对象置空,避免双重释放 s._size = 0; cout << "String移动构造" << endl; } // 移动赋值运算符 String& operator=(String&& s) noexcept { if (this != &s) { delete[] _str; // 释放现有资源 _str = s._str; // 窃取资源 _size = s._size; s._str = nullptr; // 源对象置空 s._size = 0; } cout << "String移动赋值" << endl; return *this; } ~String() { delete[] _str; } };场景2:传值返回的优化
String createString() { String str("Hello World"); // 局部对象 return str; // 返回值优化 + 移动语义 } int main() { String s = createString(); // 调用移动构造而非拷贝构造 return 0; }效率对比:
拷贝构造:分配新内存 + 复制数据 → O(n)
移动构造:指针交换 → O(1)
场景3:容器操作中的效率提升
vector<String> vec; String s("Large String"); // 传统方式:拷贝构造(低效) vec.push_back(s); // 移动语义:移动构造(高效) vec.push_back(std::move(s)); vec.emplace_back("Direct Construction"); // 最优方式3. 完美转发(Perfect Forwarding)
问题:右值引用变量在表达式中的属性是左值
解决方案:std::forward保持值的原始类别
template<typename T> void wrapper(T&& arg) { // 错误:arg是左值,总是调用左值版本 // process(arg); // 正确:保持arg的原始值类别 process(std::forward<T>(arg)); } void process(int& x) { cout << "左值" << endl; } void process(int&& x) { cout << "右值" << endl; } int main() { int a = 1; wrapper(a); // 调用process(int&) wrapper(2); // 调用process(int&&) wrapper(std::move(a)); // 调用process(int&&) }4. Lambda表达式:用法和原理
基本语法
[capture-list](parameters) -> return-type { function-body }捕获方式
int a = 1, b = 2; // 值捕获(拷贝) auto func1 = [a, b]() { return a + b; }; // 引用捕获 auto func2 = [&a, &b]() { a++; b++; }; // 隐式捕获 auto func3 = [=]() { return a + b; }; // 值捕获所有 auto func4 = [&]() { a++; b++; }; // 引用捕获所有 // 混合捕获 auto func5 = [=, &a]() { a++; }; // a引用,其他值捕获实际应用场景
// 1. 算法定制比较规则 vector<Goods> goods = {{"Apple", 9.9}, {"Banana", 5.5}}; sort(goods.begin(), goods.end(), [](const Goods& g1, const Goods& g2) { return g1.price < g2.price; // 按价格排序 }); // 2. 线程执行函数 thread t([]() { cout << "线程执行中..." << endl; }); // 3. 智能指针删除器 unique_ptr<FILE, function<void(FILE*)>> filePtr(fopen("test.txt", "r"), [](FILE* f) { if(f) fclose(f); });Lambda原理
编译器将lambda转换为仿函数类:
// lambda表达式 auto lambda = [a](int x) { return a + x; }; // 编译器生成的等价代码 class __lambda_1 { private: int a; // 捕获的变量 public: __lambda_1(int _a) : a(_a) {} int operator()(int x) const { return a + x; } };5. 综合记忆场景
场景:字符串处理管道
class StringProcessor { private: vector<string> data; public: // 添加数据(支持移动语义) template<typename T> void addData(T&& str) { data.emplace_back(std::forward<T>(str)); } // 处理数据(使用lambda) void process(function<string(string)> transformer) { for(auto& str : data) { str = transformer(str); } } // 过滤数据 vector<string> filter(function<bool(const string&)> predicate) { vector<string> result; copy_if(data.begin(), data.end(), back_inserter(result), predicate); return result; // 移动返回值优化 } }; int main() { StringProcessor processor; // 移动添加大字符串 string largeStr(1000, 'a'); processor.addData(std::move(largeStr)); // 原地处理(lambda) processor.process([](string s) { transform(s.begin(), s.end(), s.begin(), ::toupper); return s; }); // 过滤并获取结果(移动语义优化返回值) auto filtered = processor.filter([](const string& s) { return s.length() > 10; }); }关键记忆点
左值引用(&):别名已有对象,减少拷贝
右值引用(&&):接管临时对象,移动资源
移动语义:深拷贝类必备,提升容器操作效率
完美转发:模板编程中保持值类别
Lambda:就地定义函数对象,简化回调代码
返回值优化:编译器优化 + 移动语义 = 零拷贝返回
通过在实际场景中应用这些特性,可以显著提升C++程序的性能和代码简洁度。