跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

C++11 新特性深度解析:可变参数模板与 Lambda 表达式

C++11 引入多项重要特性,包括可变参数模板、移动语义、Lambda 表达式及新容器。详细解析 emplace 接口原理与优势,默认成员函数控制(default/delete),final/override 用法,以及 Lambda 表达式的语法、捕获列表与底层实现机制。结合代码示例展示 STL 变化与实践优化方案,帮助开发者掌握现代 C++ 编程技巧。

imJackJia发布于 2026/3/24更新于 2026/5/610 浏览
C++11 新特性深度解析:可变参数模板与 Lambda 表达式

C++ 学习阶段的三个参考文档

查看库文件(非官方文档): Cplusplus.com

图片

该文档在 C++98、C++11 时期尚可,之后版本支持有限。

准官方文档(同步更新): C++ 准官方参考文档

图片

包含 C++26 等最新标准,建议作为主要参考。

官方文档(类似论坛): Standard C++

图片

社区讨论活跃,适合查阅细节。

4 ~> 可变参数模版

4.5 emplace 系列接口

4.5.1 不同容器 emplace 系列接口展示

图片 图片 图片 图片

图片
图片
4.5.2 浅谈 emplace 系列接口概念
template<class... Args> void emplace_back(Args&&... args);
template<class... Args> iterator emplace(const_iterator position, Args&&... args);

C++11 以后 STL 容器新增了 emplace 系列接口。emplace 系列接口均为模板可变参数,功能上兼容 push 和 insert 系列,但 emplace 还支持直接插入构造 T 对象的参数,这样有些场景会更高效一些,可以直接在容器空间上构造 T 对象。

emplace_back 总体而言是更高效,推荐以后使用 emplace 系列替代 insert 和 push 系列。push_back 效率其实也不差,传参数包那种 emplace_back 效率才有优势,传右值传左值两者效率其实是差不多的,传 string 参数包有区别——push_back 要先移动构造再构造,emplace_back 直接构造——一步到位。

图片 图片 图片

如下图,我们模拟实现了 list 的 emplace 和 emplace_back 接口,这里把参数包不断往下传递,最终在结点的构造中直接去匹配容器存储的数据类型 T 的构造,所以达到了前面说的 emplace 支持直接插入构造 T 对象的参数,这样有些场景会更高效一些,可以直接在容器空间上构造 T 对象。

图片

传递参数包过程中,如果是 Args&&... args 的参数包,要用完美转发参数包,方式如下 std::forward<Args>(args)...,否则编译时包扩展后右值引用变量表达式就变成了左值。

4.5.3 emplace 系列接口在 list.h 文件中的使用

图片

4.5.4 emplace 系列接口在 Test.cpp 文件中的使用

图片

4.5.5 万能引用

图片 图片

5 ~> 新的类功能

5.1 默认成员函数:默认移动构造和移动赋值

原来 C++ 类中,有 6 个默认成员函数:构造函数 / 析构函数 / 拷贝构造函数 / 拷贝赋值重载 / 取地址重载 / const 取地址重载。最后重要的是前 4 个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。C++11 新增了两个默认成员函数:移动构造函数和移动赋值运算符重载。

条件苛刻: 如果你没有自己实现移动构造函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。

图片

如果你没有自己实现移动赋值重载函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节赋值,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)

图片

如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

图片

5.2 成员函数声明时要给缺省值

成员变量声明时给的缺省值(类内成员初始化)会在构造函数的初始化阶段使用。具体来说:如果某个成员变量没有在初始化列表中显式初始化,编译器会自动在初始化列表中使用这个缺省值来初始化它;如果该成员在初始化列表中被显式初始化了,那么显式初始化的值会覆盖声明时的缺省值。

5.3 default 和 delete

5.3.1 概念

C++11 可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用 default 关键字显示指定移动构造生成。

如果能想要限制某些默认函数的生成,在 C++98 中,是该函数设置成 private(私有),并且 只声明不实现,这样只要其他人想要调用就会报错。在 C++11 中更简单,只需在该函数声明加上【 = delete】即可,该语法指示编译器不生成对应函数的默认版本,称【= delete】修饰的函数为 删除函数。

5.3.2 最佳实践

如下图所示——

图片

5.4 目标构造函数和委托构造函数(了解)

5.4.1 目标构造函数

图片

5.4.2 委托构造函数

图片 图片 图片

5.4.3 最佳实践

这两个函数了解即可,本文简单演示了一下——

图片

5.5 final 和 override

final 和 override 我们在继承和多态那个章节已经进行了详细讲过了,读者如果忘了可以回顾相关章节。

图片 图片

这里重新展示一下关于 final 和 override 的思维导图——

图片

6 ~> C++11:STL 的变化

6.1 新的容器

下面这张图中圈起来的就是 C++11 的 STL 中的新增容器,但是实际中最有用的是 unordered_map 和 unordered_set。 C++11 新增容器:array、forward_list(单链表)、unordered_map 和 unordered_set(真正有用的就这俩)——

图片

这两个我们前面已经进行了非常详细的介绍,其他的大家了解一下即可。

6.2 新的接口

STL 中容器的新接口也不少,最重要的就是右值引用和移动语义相关的 push / insert / emplace 系列接口(插入数据系列的接口);移动构造和移动赋值(雪中送炭),还有 initializer_list 版本的构造(锦上添花的作用)等,这些前面都讲过了,还有一些无关痛痒的 cbegin / cend 等需要时查查文档即可。

6.3 宝藏:范围 for

容器的范围 for 遍历,这个在容器部分也讲过了。

图片

7 ~> lambda

7.1 lambda 表达式的语法

图片

7.1.1 概念

lambda 表达式本质是一个匿名函数对象,跟普通函数不同的是:lambda 表达式可以定义在函数内部。

lambda 表达式语法使用层而言没有类型,所以我们 一般是用 auto 或者模板参数定义的对象去接收 lambda 对象。

lambda 表达式的格式:

[capture-list] (parameters) -> return type { function body }

[ capture-list ]:捕捉列表,该列表总是出现在 lambda 函数的开始位置,编译器根据 [] 来判断接下来的代码是否为 lambda 函数,捕捉列表能够捕捉上下文中的变量供 lambda 函数使用,捕捉列表可以传值和传引用捕捉,具体细节在下面介绍捕捉列表的部分再细说。捕捉列表为空也不能省略。

( parameters ):参数列表,与普通函数的参数列表功能类似,如果不需要参数传递,则可以连同 () 一起省略

->returntype:返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。一般返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

{functionbody}:函数体,函数体内的实现跟普通函数完全类似,在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量,函数体为空也不能省略。

图片

7.1.2 最佳实践

图片

7.2 lambda 的应用场景

7.2.1 说明

在介绍 lambda 表达式之前,我们的使用的可调用对象只有函数指针和仿函数对象,函数指针的类型定义起来比较麻烦,仿函数要定义一个类,相对会比较麻烦。使用 lambda 去定义可调用对象,既简单又方便。

lambda 在很多其他地方用起来也很好用。比如线程中定义线程的执行函数逻辑,智能指针中定制删除器等, lambda 的应用还是很广泛的,以后我们会不断接触到,主要这个是一个我们之前没有接触过的新知识点,开发者要留意一下哦!

7.2.2 最佳实践
struct Goods {
    string _name; // 名字
    double _price; // 价格
    int _evaluate; // 评价
    // ...
    Goods(const char* str, double price, int evaluate) : _name(str), _price(price), _evaluate(evaluate) {}
};

struct ComparePriceLess {
    bool operator()(const Goods& gl, const Goods& gr) {
        return gl._price < gr._price;
    }
};

struct ComparePriceGreater {
    bool operator()(const Goods& gl, const Goods& gr) {
        return gl._price > gr._price;
    }
};

struct CompareEvaluateGreater {
    bool operator()(const Goods& gl, const Goods& gr) {
        return gl._evaluate < gr._evaluate;
    }
};

struct CompareEvaluateLess {
    bool operator()(const Goods& gl, const Goods& gr) {
        return gl._evaluate < gr._evaluate;
    }
};

int main() {
    vector<Goods> v = {{"苹果", 2.1, 5}, {"香蕉", 3, 4}, {"橙子", 2.2, 3}, {"菠萝", 1.5, 4}};
    // 类似这样的场景,我们实现仿函数对象或者函数指针支持商品中 
    // 不同项的比较,相对还是比较麻烦的,那么这里 lambda 就很好用了
    //sort(v.begin(), v.end(), ComparePriceLess());
    //sort(v.begin(), v.end(), ComparePriceGreater());
    //sort(v.begin(), v.end(), CompareEvaluateLess());
    //sort(v.begin(), v.end(), CompareEvaluateGreater());
    //auto priceLess = [](const Goods& gl, const Goods& gr) {
    //    return gl._price < gr._price;
    //};
    //sort(v.begin(), v.end(), priceLess);
    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._price < gr._price; });
    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._price > gr._price; });
    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._evaluate < gr._evaluate; });
    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._evaluate > gr._evaluate; });
    return 0;
}

大家应该注意到了被注释掉的代码段其实就是用到了我们的 lambda 表达式,这四个比较的仿函数,用 lambda 表达式只要一段代码就能完成,这就是 lambda 表达式,非常的方便。原理部分详细介绍一下——其实 lambda 原理和同样是 C++11 更新的内容——范围 for——的原理很类似,这里的'很像'不是指 lambda 的原理也是底层被替换成迭代器(lambda 的底层是一个 operator(),`编译器会帮你生成一个仿函数,)这里我们说的'很像',指的是 lambda 和范围 for 都是编译器帮你生成!

7.3 捕捉列表(*)

7.3.1 概念

lambda 表达式中默认只能用 lambda 函数体和参数中的变量,如果想用外层作用域中的变量就需要进行捕捉

第一种捕捉方式 是在捕捉列表中显示的传值捕捉和传引用捕捉,捕捉的多个变量用逗号分割。[x,y,&z] 表示 x 和 y 是值捕捉,z 是引用捕捉。

第二种捕捉方式 是在捕捉列表中隐式捕捉,我们在捕捉列表写一个=表示隐式值捕捉,在捕捉列表写一个&表示隐式引用捕捉,这样我们 lambda 表达式中用了那些变量,编译器就会自动捕捉那些变量。

第三种捕捉方式 是在捕捉列表中混合使用隐式捕捉和显示捕捉。[=,&X 表示其他变量隐式值捕捉,x 引用捕捉;[&,X,y 表示其他变量引用捕捉,x 和 y 值捕捉。当使用混合捕捉时,第一个元素必须是& 或 =,并且&混合捕捉时,后面的捕捉变量必须是值捕捉,同理=混合捕捉时,后面的捕捉变量必须是引用捕捉。

lambda 表达式如果在函数局部域中,他可以捕捉 lambda 位置之前定义的变量,不能捕捉静态局部变量和全局变量,静态局部变量和全局变量也不需要捕捉, lambda 表达式中可以直接使用。这也意味着 lambda 表达式如果定义在全局位置,捕捉列表必须为空。

默认情况下, lambda 捕捉列表是被 const 修饰的,也就是说传值捕捉的过来的对象不能修改,mutable 加在参数列表的后面可以取消其常量性,也就说使用该修饰符后,传值捕捉的对象就可以修改了,但是修改还是形参对象,不会影响实参。使用该修饰符后,参数列表不可省略(即使参数为空)。

图片

7.3.2 最佳实践

图片

看一下 main 函数——

图片

7.4 lambda 的原理

7.4.1 原理

lambda 的原理和范围 for 很像,编译后从汇编指令层的角度看,压根就没有 lambda 和范围 for 这样的东西。范围 for 底层是迭代器,而 lambda 底层是仿函数对象,也就说我们写了一个 lambda 以后,编译器会生成一个对应的仿函数的类。

仿函数的类名是编译按一定规则生成的,保证不同的 lambda 生成的类名不同,**lambda 参数 / 返回类型 / 函数体就是仿函数 operator() 的参数/返回类型/函数体**,lambda 的捕捉列表本质是生成的仿函数类的成员变量——也就是说捕捉列表的变量都是 lambda 类构造函数的实参,当然隐式捕捉不同,编译器也不是傻瓜,实际上,编译器看使用哪些就传哪些对象。

7.4.2 最佳实践

我们实践一下——

语法层拿不到 lambda 的类型,不是说没有类型,而是我们拿不到,但是编译器能够拿到。

简而言之,如下图所示——

图片

7.4.3 捕捉列表就是仿函数的成员函数

捕捉列表就是仿函数的成员函数——

图片

7.4.4 补充:成员函数中写了 lambda

图片

也可以修改成员变量,这里 this 捕捉的本质是 lambda 可以访问成员变量。

注意:局部的静态变量和全局的全局变量,不用也不能捕捉(两者的生命周期在全局)!

C++11 完整代码示例与实践演示

list.h:

#pragma once
namespace jqj {
// --------------链表节点结构--------------
template<class T>
struct list_node {
    list_node<T>* _next; // 指向下一个节点的指针
    list_node<T>* _prev; // 指向前一个节点的指针
    T _data;             // 节点存储的数据
    // --------------节点构造函数--------------
    list_node(const T& x = T()) : _next(nullptr), _prev(nullptr), _data(x) // x 节点数据,默认为 T 类型的默认值
    {}
};

// --------------链表迭代器--------------
// 实现双向迭代器功能,支持前向和后向遍历
template<class T, class Ref, class Ptr>
// T 数据类型
// Ref 引用类型(T& 或 const T&)
struct list_iterator {
    using Self = list_iterator<T, Ref, Ptr>; // 自身类型
    using Node = list_node<T>;               // 节点类型
    Node* _node;                             // 当前指向的节点指针

    // 迭代器构造函数
    list_iterator(Node* node) : _node(node) {}

    // 迭代器解引用操作
    // *it = 1
    Ref operator*() // 解引用,Ref 就是 reference,引用的意思
    {
        return _node->_data;
    }
    Ptr operator->() // 返回对应数据类型的指针
    {
        return &_node->_data;
    }

    // ++it // 前向迭代操作
    Self& operator++() // Self& 返回递增后的迭代器引用
    {
        _node = _node->_next;
        return *this;
    }
    Self operator++(int) // Self 返回递增前的迭代器副本
    {
        Self tmp(*this);
        _node = _node->_next;
        return tmp;
    }

    // --it // 后向迭代操作
    Self& operator--() // Self& 返回递减后的迭代器引用
    {
        _node = _node->_prev;
        return *this;
    }
    Self operator--(int) // Self 返回递减前的迭代器副本
    {
        Self tmp(*this);
        _node = _node->_prev;
        return tmp;
    }

    // 迭代器比较操作
    bool operator!=(const Self& s) const // bool 两个迭代器是否不指向同一节点
    {
        return _node != s._node;
    }
    bool operator==(const Self& s) const // bool 两个迭代器是否不指向同一节点
    {
        return _node == s._node;
    }
};

// --------------链表主体类--------------
template<class T>
class list {
    using Node = list_node<T>; // 节点类型别名
public:
    // 迭代器类型定义
    using iterator = list_iterator<T, T&, T*>;   // 普通迭代器
    using const_iterator = list_iterator<T, const T&, const T*>; // 常量迭代器
    // const T* 只能读数据,不能修改数据

    // --------------迭代器访问接口--------------
    // 获取指向第一个元素的迭代器
    // iterator 指向首元素的迭代器
    iterator begin() { return iterator(_head->_next); }
    // iterator 指向哨兵节点的迭代器
    iterator end() { return iterator(_head); }
    // 获取指向第一个元素的常量迭代器
    // const_iterator 指向首元素的常量迭代器
    const_iterator begin() const { return const_iterator(_head->_next); }
    // const_iterator 指向哨兵节点的常量迭代器
    const_iterator end() const { return const_iterator(_head); }

    // ----------------链表初始化相关-----------------
    void empty_init() // 初始化空链表(创建哨兵节点)
    {
        _head = new Node;
        _head->_next = _head;
        _head->_prev = _head;
    }
    // 默认构造函数
    list() { empty_init(); }
    // 初始化列表构造函数
    // il 初始化列表
    list(initializer_list<T> il) {
        empty_init();
        for (auto& e : il) {
            push_back(e);
        }
    }
    // 范围构造函数
    // InputIterator 输入迭代器类型
    template<class InputIterator>
    list(InputIterator first, InputIterator last) // first 范围起始迭代器 // last 范围结束迭代器
    {
        empty_init();
        while (first != last) {
            push_back(*first);
            ++first;
        }
    }
    // 数量构造函数(size_t 版本)
    list(size_t n, T val = T()) // val 元素值,默认为 T 的默认值
    {
        empty_init();
        for (size_t i = 0; i < n; ++i) {
            push_back(val);
        }
    }
    // 数量构造函数(int 版本)
    list(int n, T val = T()) // val 元素值,默认为 T 的默认值
    {
        empty_init();
        for (size_t i = 0; i < n; ++i) {
            push_back(val);
        }
    }

    // -------------析构函数-------------
    // 清理所有节点并释放哨兵节点
    ~list() {
        clear();
        delete _head;
        _head = nullptr;
        _size = 0;
    }

    // -----------拷贝控制函数----------
    // lt 要拷贝的源链表
    // ------------传统写法------------
    // lt2(lt1)
    list(const list<T>& lt) {
        empty_init();
        for (auto& e : lt) {
            push_back(e);
        }
    }
    // 拷贝赋值运算符
    // lt 要拷贝的源链表
    // list<T>& 返回当前链表的引用
    // lt1 = lt3
    list<T>& operator=(const list<T>& lt) {
        if (this != &lt) {
            clear();
            for (auto& e : lt) {
                push_back(e);
            }
        }
        return *this;
    }

    // ----------------容量操作---------------
    // 交换两个链表的内容
    void swap(list<T>& lt) // lt 要交换的另一个链表
    {
        std::swap(_head, lt._head);
        std::swap(_size, lt._size);
    }
    // 清空链表中的所有元素
    // 保留哨兵节点,删除所有数据节点
    void clear() {
        iterator it = begin();
        while (it != end()) {
            it = erase(it);
        }
    }
    template<class... Args>
    void emplace_back(Args&&... args) {
        emplace(end(), args...);
        emplace(end(), forward<Args>(args)...);
    }
    template<class... Args>
    void emplace(iterator pos, Args&&... args) {
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* newnode = new Node(forward<Args>(args)...); // prev newnode cur
        prev->_next = newnode;
        newnode->_prev = prev;
        newnode->_next = cur;
        cur->_prev = newnode;
        ++_size;
    }
    void push_back(T&& x) {
        insert(end(), forward<T>(x));
    }
    // 在链表头部插入元素,x:要插入的元素值
    void push_front(const T& x) {
        insert(begin(), x);
    }
    // 删除链表尾部元素
    void pop_back() {
        erase(--end());
    }
    // 删除链表头部元素
    void pop_front() {
        erase(begin());
    }
    void insert(iterator pos, const T& x) // pos:插入位置的迭代器,x:要插入的元素值
    {
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* newnode = new Node(x); // // 连接新节点:prev -> newnode -> cur
        // prev newnode cur
        prev->_next = newnode;
        newnode->_prev = prev;
        newnode->_next = cur;
        cur->_prev = newnode;
        ++_size;
    }
    void insert(iterator pos, T&& x) // pos:插入位置的迭代器,x:要插入的元素值
    {
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* newnode = new Node(move(x)); // // 连接新节点:prev -> newnode -> cur
        // prev newnode cur
        prev->_next = newnode;
        newnode->_prev = prev;
        newnode->_next = cur;
        cur->_prev = newnode;
        ++_size;
    }
    // 删除指定位置的元素
    iterator erase(iterator pos) // iterator 返回指向被删除元素后一个元素的迭代器
    {
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* next = cur->_next; // 跳过被删除节点:prev -> next
        prev->_next = next;
        next->_prev = prev;
        delete cur;
        --_size;
        /*return iterator(next);*/
        return next; /// 返回下一个节点的迭代器
        // 两种写法都可以
    }

    // -------------- 容量信息 ------------------
    size_t size() const {
        // size_t n = 0;
        // for (auch e : *this)
        // {
        //     ++n;
        // }
        // return n;
        return _size;
    }

private:
    Node* _head; // 哨兵头节点指针
    size_t _size = 0; // 链表元素个数计数器
};
}

test.cpp:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <string>
using namespace std;
#include <assert.h>
#include <algorithm>

namespace Alice {
class string {
public:
    typedef char* iterator;
    typedef const char* const_iterator;
    iterator begin() { return _str; }
    iterator end() { return _str + _size; }
    const_iterator begin() const { return _str; }
    const_iterator end() const { return _str + _size; }

    string(const char* str = "") : _size(strlen(str)), _capacity(_size) {
        cout << "string(char* str)-构造" << endl;
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }

    void swap(string& s) {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }

    // 拷贝构造
    string(const string& s) {
        cout << "string(char* str)-拷贝构造" << endl;
        reserve(s._capacity);
        for (auto ch : s) {
            push_back(ch);
        }
    }

    // 移动构造
    string(string&& s) {
        cout << "string(char* str)-移动构造" << endl;
        swap(s); // 交换后 s 持有原对象的资源
    }
    // s 析构时会释放原对象的资源,但原对象现在持有什么?

    string& operator=(const string& s) {
        cout << "string(char* str)-拷贝赋值" << endl;
        if (this != &s) {
            _str[0] = '\0';
            _size = 0;
            reserve(s._capacity);
            for (auto ch : s) {
                push_back(ch);
            }
        }
        return *this;
    }

    // 移动赋值
    string& operator=(string&& s) {
        cout << "string(char* str)-移动赋值" << endl;
        swap(s); // 和上面同样的问题
        return *this;
    }

    ~string() {
        //cout << "~string() -- 析构" << endl;
        delete[] _str;
        _str = nullptr;
    }

    char& operator[](size_t pos) {
        assert(pos < _size);
        return _str[pos];
    }

    void reserve(size_t new_capacity) {
        // int n = 0; // 触发 assert 的报错机制
        if (new_capacity > _capacity) {
            char* tmp = new char[new_capacity + 1];
            if (_str) {
                strcpy(tmp, _str); // 包括 null 终止符
                delete[] _str;
            }
            _str = tmp;
            _capacity = new_capacity;
        }
    }

    void push_back(char ch) {
        if (_size >= _capacity) {
            size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
            reserve(newcapacity);
        }
        _str[_size] = ch;
        ++_size;
        _str[_size] = '\0';
    }

    string& operator+=(char ch) {
        push_back(ch);
        return *this;
    }

    const char* c_str() const { return _str; }
    size_t size() const { return _size; }

private:
    char* _str = nullptr;
    size_t _size = 0;
    size_t _capacity = 0;
};

// 右值引用和移动语义解决传值返回问题
// 传值返回需要拷贝
string addStrings(string num1, string num2) {
    string str;
    int end1 = num1.size() - 1, end2 = num2.size() - 1;
    // 进位
    int next = 0;
    while (end1 >= 0 || end2 >= 0) {
        int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
        int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
        int ret = val1 + val2 + next;
        next = ret / 10;
        ret = ret % 10;
        str += ('0' + ret);
    }
    if (next == 1) str += '1';
    reverse(str.begin(), str.end());
    cout << &str << endl;
    return str;
}
}

// emplace_back 总体而言是更加高效的,推荐以后使用 emplace 系列替代 insert 和 push 系列

//int main()
//{
//    list<Alice::string> lt;
//
//    // 传左值,跟 push_back 一样,走拷贝构造
//    Alice::string s1("111111111111111111");
//    lt.emplace_back(s1);
//    cout << "**************************" << endl;
//
//    // 传右值,跟 push_back 一样,走移动构造
//    lt.emplace_back(move(s1));
//    cout << "**************************" << endl;
//
//    // 直接把构造 string 参数包往下传,直接用 string 参数包构造 string
//    // 这里达到的效果是 push_back 做不到的
//    lt.push_back("111111111111111111");
//    cout << "**************************" << endl;
//
//    lt.emplace_back("111111111111111111");
//    cout << "****************************" << endl;
//
//    // 运行结果:
//    // string(char* str) - 构造
//    // string(char* str) - 拷贝构造
//    // **************************
//    // string(char* str) - 移动构造
//    // **************************
//    // string(char* str) - 构造
//    // string(char* str) - 移动构造
//    // **************************
//    // string(char* str) - 构造
//    // ****************************
//
//    return 0;
//}

// 日期类
struct Date {
    int _y;
    int _m;
    int _d;
    Date(int year, int month, int day) : _y(year), _m(month), _d(day) {}
};

//int main()
//{
//    list<pair<Alice::string, int>> lt1;
//
//    // 跟 push_back 一样
//    // 构造 pair + 拷贝/移动构造 pair 到 list 的节点中 data 上
//    pair<Alice::string, int> kv("苹果", 1);
//    lt1.emplace_back(kv);
//    cout << "****************************" << endl;
//
//    // 跟 push_back 一样
//    lt1.emplace_back(move(kv));
//    cout << "****************************" << endl;
//
//    // 直接把构造 pair 参数包往下传,直接用 pair 参数包构造 pair
//    // 这里达到的效果是 push_back 做不到的
//    lt1.emplace_back("苹果", 1);
//    //lt1.push_back("苹果", 1); // 错误,要传 pair 或者{}隐式转换 pair 的值
//    //lt1.push_back({"苹果", 1}); // 要传 pair 或者{}隐式转换 pair 的值
//    cout << "****************************" << endl;
//
//    list<Date> lt;
//    // 构造 + 拷贝构造
//    Date d1{ 2025,11,18 };
//    lt.push_back(d1);
//
//    lt.push_back({ 2025, 11, 18 });
//
//    // 传构造 Date 的参数,传给形参参数包,参数包往下不断传递,最后直接构造到链表节点上
//    // 直接构造
//    lt.emplace_back(2025, 11, 18);
//
//    // 运行结果:
//    // string(char* str) - 构造
//    // string(char* str) - 拷贝构造
//    // ****************************
//    // string(char* str) - 移动构造
//    // ****************************
//    // string(char* str) - 构造
//    // ****************************
//
//    return 0;
//}

//#include"list.h"
//
//int main()
//{
//    list<pair<Alice::string, int>> lt1;
//    cout << "****************************" << endl;
//
//    // 跟 push_back 一样
//    // 构造 pair + 拷贝/移动构造 pair 到 list 的节点中 data 上
//    pair<Alice::string, int> kv("苹果", 1);
//    lt1.emplace_back(kv);
//    cout << "****************************" << endl;
//
//    // 跟 push_back 一样
//    lt1.emplace_back(move(kv));
//    cout << "****************************" << endl;
//
//    // 直接把构造 pair 参数包往下传,直接用 pair 参数包构造 pair
//    // 这里达到的效果是 push_back 做不到的
//    lt1.emplace_back("苹果", 1); // 推荐
//    //lt1.emplace_back({"苹果", 1}); // 错误
//    //lt1.push_back("苹果", 1); // 错误,要传 pair 或者{}隐式转换 pair 的值
//    //lt1.push_back({"苹果", 1}); // 要传 pair 或者{}隐式转换 pair 的值
//    cout << "****************************" << endl;
//
//    list<Date> lt;
//    // 构造 + 拷贝构造
//    Date d1{ 2025,11,18 };
//    lt.push_back(d1);
//    lt.push_back({ 2025, 11, 18 });
//
//    // 传构造 Date 的参数,传给形参参数包,参数包往下不断传递,最后直接构造到链表节点上
//    // 直接构造
//    lt.emplace_back(2025, 11, 18);
//
//    return 0;
//}

//class Person
//{
//public:
//    Person(const char* name = "艾莉丝 wmwmwmwwmmwmwmwmwwmmwwmmw", int age = 18)
//        :_name(name)
//        ,_age(age)
//    { }
//
//    // C++11
//    Person(const Person& p) = delete;
//    Person(Person&& p) = default;
//
//    ~Person()
//    { }
//
//private:
//    //// C++98
//    //Person(const Person& p);
//
//    Alice::string _name;
//    int _age;
//};
//
//int main()
//{
//    Person s1;
//    //Person s2 = s1;
//    Person s3 = std::move(s1);
//
//    //Person s4("xxxxxxxxxxxxxxxxxxxxxxxxxxx", 18);
//    //s4 = std::move(s2);
//
//    // 输出
//    // string(char* str)-构造
//    // string(char* str) - 移动构造
//
//    return 0;
//}

//#include<iostream>
//using namespace std;
//
//class Example
//{
//public:
//    Example(int a, int b)
//        :_x(a)
//        ,_y(b)
//    {
//        cout << "目标构造函数\n";
//    }
//
//    // 委托构造:类似于派生类复用基类
//    Example(int a)
//        :Example(a, 0)
//    {
//        cout << "委托构造函数\n";
//    }
//
//    int _x;
//    int _y;
//};
//
//class Time //
//{
//public:
//    Time(int h, int m)
//        :_hour(h)
//        ,_minute(m)
//    { }
//
//    // 'Time': 对委托构造函数的调用应仅为成员初始值设定项
//    // '_second': 已初始化
//    Time(int h, int m, int s)
//        :Time(h, m)
//        ,_second(s)
//    { }
//
//private:
//    int _hour;
//    int _minute;
//    int _second = 0;
//};
//
//int main()
//{
//    Example(1, 2);
//    Example(1);
//
//    // 输出:
//    // 目标构造函数
//    // 目标构造函数
//    // 委托构造函数
//
//    return 0;
//}

//class Base
//{
//public:
//    Base(int x, double d)
//        :_x(x)
//        ,_d(d)
//    { }
//
//    Base(int x)
//        :_x(x)
//    { }
//
//    Base(double d)
//        :_d(d)
//    { }
//
//protected:
//    int _x = 0;
//    double _d = 0.0;
//};
//////// 传统的派生类实现构造
////class Dervied :public Base
////{
////public:
////    Dervied(int x):Base(x){}
////    Dervied(double d):Base(d){}
////    Dervied(int x,double d):Base(x,d){}
////};
////
// C++11 继承基类的所有构造函数
//class Dervied :public Base
//{
//public:
//    using Base::Base;
//
//protected:
//    int _i = 0;
//    string _s;
//};
//
//// 非常长
//std::map<std::string, std::pair<std::string, std::string>>::iterator func();
//auto func() -> std::map<std::string, std::pair<std::string, std::string>>::iterator;
//
//int main()
//{
//    Dervied d1(1);
//    Dervied d2(1.1);
//    Dervied d3(2, 2.2);
//
//    return 0;
//}

// ==========================lambda==========================
// -----------------------lambda 表达式语法--------------------------
//int main()
//{
//    //一个简单的 lambda 表达式
//    //auto add1 = [](int x, int y)->int {return x + y; };
//
//    auto add1 = [](int x, int y) { return x + y; }; // 返回值类型可写可不写,编译器会自动推导
//    cout << add1(1, 2) << endl;
//
//    // 1、捕捉为空也不能省略
//    // 2、参数为空可以省略
//    // 3、返回值可以省略,可以通过返回对象自动推导
//    // 4、函数题不能省略
//    auto func1 = []
//    {
//        cout << "hello Alice" << endl;
//        return 0;
//    };
//    func1();
//
//    int a = 0, b = 1;
//    auto swap1 = [](int& x, int& y)
//    {
//        int tmp = x;
//        x = y;
//        y = tmp;
//    };
//    swap1(a, b);
//    cout << a << ":" << b << endl;
//
//    // 输出:
//    // 3
//    // hello Alice
//    // 1:0
//
//    return 0;
//}

// ---------------------------lambda 的应用-------------------------------
//struct Goods
//{
//    string _name; // 名字
//    double _price; // 价格
//    int _evaluate; // 评价
//
//    // ...
//    Goods(const char* str, double price, int evaluate)
//        :_name(str)
//        ,_price(price)
//        ,_evaluate(evaluate)
//    { }
//};
//
//struct ComparePriceLess
//{
//    bool operator()(const Goods& gl, const Goods& gr)
//    {
//        return gl._price < gr._price;
//    }
//};
//
//struct ComparePriceGreater
//{
//    bool operator()(const Goods& gl, const Goods& gr)
//    {
//        return gl._price > gr._price;
//    }
//};
//
//struct CompareEvaluateGreater
//{
//    bool operator()(const Goods& gl, const Goods& gr)
//    {
//        return gl._evaluate < gr._evaluate;
//    }
//};
//
//struct CompareEvaluateLess
//{
//    bool operator()(const Goods& gl, const Goods& gr)
//    {
//        return gl._evaluate < gr._evaluate;
//    }
//};
//
//int main()
//{
//    vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3}, { "菠萝", 1.5, 4 } };
//
//    // 类似这样的场景,我们实现仿函数对象或者函数指针支持商品中
//    // 不同项的比较,相对还是比较麻烦的,那么这里 lambda 就很好用了
//    //
//    //sort(v.begin(), v.end(), ComparePriceLess());
//    //sort(v.begin(), v.end(), ComparePriceGreater());
//    //sort(v.begin(), v.end(), CompareEvaluateLess());
//    //sort(v.begin(), v.end(), CompareEvaluateGreater());
//
//    //auto priceLess = [](const Goods& gl, const Goods& gr)
//    //{
//    //    return gl._price < gr._price;
//    //};
//
//    //sort(v.begin(), v.end(), priceLess);
//
//    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) {
//        return gl._price < gr._price;
//    });
//
//    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) {
//        return gl._price > gr._price;
//    });
//
//    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) {
//        return gl._evaluate < gr._evaluate;
//    });
//
//    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) {
//        return gl._evaluate > gr._evaluate;
//    });
//
//    return 0;
//}

// --------------------------捕捉列表-------------------------
int x = 0;
// 捕捉列表必须为空,因为全局变量不用捕捉就可以用,没有可被捕捉的变量
auto func1 = []() { x++; };

class A {
public:
    void Func() {
        int x = 0, y = 1;
        // 隐式捕捉
        auto f1 = [=] { _a1++; return x + y + _a1 + _a2; };
        cout << f1() << endl;
        auto f2 = [&] { x++; _a1++; return x + y + _a1 + _a2; };
        cout << f2() << endl;
        // 捕捉 this 本质是可以访问成员变量
        auto f3 = [x, this] { _a1++; return x + _a1 + _a2; };
        cout << f3() << endl;
    }
private:
    int _a1 = 0;
    int _a2 = 1;
};

int main() {
    // 只能用当前 lambda 局部域捕捉的对象和全局对象
    // 捕获列表的意义,本质更方便的使用当前局部域的对象
    int a = 0, b = 1, c = 2, d = 3;
    // auto func1=[a,&b] () mutable
    auto func1 = [a, &b] {
        // 值捕捉的变量不能修改,引用捕捉的变量可以修改
        // a++ b++;
        int ret = a + b;
        x++;
        return ret;
    };
    cout << func1() << endl;

    // 隐式值捕捉
    // 用了哪些变量就捕捉哪些变量
    auto func2 = [=] {
        int ret = a + b + c;
        return ret;
    };
    cout << func2() << endl;

    // 隐式值捕捉
    // 用了哪些变量就捕捉哪些变量
    auto func3 = [&] { a++; c++; d++; };
    func3();
    cout << a << " " << b << " " << c << " " << d << endl;

    // 混合捕捉 1
    auto func4 = [& , a, b] {
        //a++;
        //b++;
        c++; d++;
        return a + b + c + d;
    };
    func4();
    cout << a << " " << b << " " << c << " " << d << endl;

    // ----------------验证:lambda 底层是编译器生成的仿函数(更轻量级的)-------------------
    // 仿函数
    //class lambda5
    //{
    //public:
    //    lambda5(int a_, int b_)
    //        :a(a_)
    //        ,b(b_)
    //    { }
    //    int operator()(int x)
    //    {
    //        ++b;
    //        return a + b + x;
    //    }
    //private:
    //    const int a;
    //    int& b;
    //};

    // 运行结果:
    // 2
    // 4
    // 1 2 3 4
    // 1 2 4 5
    // lambda
    auto func5 = [a, &b](int x) { ++b; return a + b + x; };
    // 等价于
    // lambda func5(a, b);func5(1);

    // 运行结果:
    // 2
    // 4
    // 1 2 3 4
    // 1 2 4 5
    // 结果完全一样!猜想得到验证!
    return 0;
}

目录

  1. C++ 学习阶段的三个参考文档
  2. 4 ~> 可变参数模版
  3. 4.5 emplace 系列接口
  4. 4.5.1 不同容器 emplace 系列接口展示
  5. 4.5.2 浅谈 emplace 系列接口概念
  6. 4.5.3 emplace 系列接口在 list.h 文件中的使用
  7. 4.5.4 emplace 系列接口在 Test.cpp 文件中的使用
  8. 4.5.5 万能引用
  9. 5 ~> 新的类功能
  10. 5.1 默认成员函数:默认移动构造和移动赋值
  11. 5.2 成员函数声明时要给缺省值
  12. 5.3 default 和 delete
  13. 5.3.1 概念
  14. 5.3.2 最佳实践
  15. 5.4 目标构造函数和委托构造函数(了解)
  16. 5.4.1 目标构造函数
  17. 5.4.2 委托构造函数
  18. 5.4.3 最佳实践
  19. 5.5 final 和 override
  20. 6 ~> C++11:STL 的变化
  21. 6.1 新的容器
  22. 6.2 新的接口
  23. 6.3 宝藏:范围 for
  24. 7 ~> lambda
  25. 7.1 lambda 表达式的语法
  26. 7.1.1 概念
  27. 7.1.2 最佳实践
  28. 7.2 lambda 的应用场景
  29. 7.2.1 说明
  30. 7.2.2 最佳实践
  31. 7.3 捕捉列表(*)
  32. 7.3.1 概念
  33. 7.3.2 最佳实践
  34. 7.4 lambda 的原理
  35. 7.4.1 原理
  36. 7.4.2 最佳实践
  37. 7.4.3 捕捉列表就是仿函数的成员函数
  38. 7.4.4 补充:成员函数中写了 lambda
  39. C++11 完整代码示例与实践演示
  40. list.h:
  41. test.cpp:
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 简单的解压缩算法实现
  • FPGA 实现 CAN 总线接口与数据帧解析实战
  • 线性动态规划:四道经典例题实战解析
  • MySQL 数据库管理基础:视图操作与用户权限管理
  • C++ 设计模式:单例模式
  • Python 性能调优:cProfile 与火焰图实战
  • 五分钟构建动态知识图谱:利用大模型提取实体关系与数据对话
  • Spring Boot 3 开源项目 ems4j:构建完整的能耗管理与 IoT 远程控表链路
  • AI、机器学习与深度学习的本质区别及落地选型指南
  • C++ 线程库与多线程编程核心机制解析
  • Windows 下 WSL Ubuntu 系统从 C 盘迁移至 D 盘操作指南
  • JVM 对象引用定位机制:句柄池与直接指针
  • AI 辅助图书出版:变现路径与原创性挑战分析
  • Python 爬虫项目:爬取 B 站直播弹幕数据
  • C++26 任务优先级机制设计与实现
  • UE5.2 引擎源码编译 C4756 常量算法溢出问题及解决
  • KiCad 符号编辑器引脚添加与同步机制解析
  • 多模态动态融合模型 PDF:理论解读、代码修复与参数详解
  • Spring Cloud Nacos 微服务注册发现与配置中心实践
  • Solr 配置停止词与排除词(mmseg4j 版)

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online