跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

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

C++11 引入多项重要特性,包括可变参数模板、移动语义、右值引用及 Lambda 表达式。文章详细解析了 emplace 系列接口在容器中的高效用法,对比了 push_back 与 insert 的性能差异。阐述了默认成员函数、move 构造、default/delete 关键字的使用场景。介绍了 final 和 override 在继承控制中的作用。涵盖 STL 新增容器如 unordered_map/set,以及范围 for 循环。重点讲解 Lambda 表达式的语法、捕捉列表机制(传值/传引用)、底层仿函数原理及应用场景,如排序比较器替代。提供完整链表实现与测试代码示例。

佛系玩家发布于 2026/3/27更新于 2026/9/1061 浏览
C++11 新特性深度解析:可变参数模板与 Lambda 表达式

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

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

这个文档在 C++98、C++11 时候还行,之后就完全没法用了……

准官方文档(同步更新)——还 可以看语法:C++ 准官方参考文档

这个行,包括 C++26 都同步了,以后主要会看这个。

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

这个网站上面会有很多大佬,类似于论坛。

4 ~> 可变参数模版

4.5 emplace 系列接口

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

C++11 以后 STL 容器新增了 emplace 系列的接口,emplace 系列的接口均为模板可变参数,功能上兼容 push 和 insert 系列,但是 emplace 还支持新玩法。假设容器为 container,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 返回节点数据的引用(可读或可写)
    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.3 emplace 系列接口在 list.h 文件中的使用
  6. 4.5.4 emplace 系列接口在 Test.cpp 文件中的使用
  7. 4.5.5 万能引用
  8. 5 ~> 新的类功能
  9. 5.1 默认成员函数:默认移动构造和移动赋值
  10. 5.2 成员函数声明时要给缺省值
  11. 5.3 default 和 delete
  12. 5.3.1 概念
  13. 5.3.2 最佳实践
  14. 5.4 目标构造函数和委托构造函数(了解)
  15. 5.4.1 目标构造函数
  16. 5.4.2 委托构造函数
  17. 5.4.3 最佳实践
  18. 5.5 final 和 override
  19. 6 ~> C++11:STL 的变化
  20. 6.1 新的容器
  21. 6.2 新的接口
  22. 6.3 宝藏:范围 for
  23. 7 ~> lambda
  24. 7.1 lambda 表达式的语法
  25. 7.1.1 概念
  26. 7.1.2 最佳实践
  27. 7.2 lambda 的应用场景
  28. 7.2.1 说明
  29. 7.2.2 最佳实践
  30. 7.3 捕捉列表(*)
  31. 7.3.1 概念
  32. 7.3.2 最佳实践
  33. 7.4 lambda 的原理
  34. 7.4.1 原理
  35. 7.4.2 最佳实践
  36. 7.4.3 捕捉列表就是仿函数的成员函数
  37. 7.4.4 补充:成员函数中写了 lambda
  38. C++11 完整代码示例与实践演示
  39. list.h:
  40. Test.cpp:

更多推荐文章

查看全部
  • n8n 与私有 AI 模型本地化部署实战指南
  • C++ 内核性能优化十大误区:如何避免常见陷阱
  • Stable Yogi 皮衣穿搭工具:历史记录管理与图片批量导出
  • AI 辅助编程的边界探索:当 Copilot 学会写测试
  • 安路 FPGA 下载器驱动安装与测试指南
  • C++ 容器适配器与核心数据结构精解:栈、队列、deque 底层实现与实战应用
  • 26 年网络建设与运维样题一网络建设与调试模块完整配置方案
  • Stable Diffusion 模型下载器使用教程
  • python-docx-template 模板化生成 Word 文档指南
  • MAX4466 模拟麦克风语音前端放大电路设计与调试
  • 用 Prompt 生成正则表达式进行文本匹配
  • 零基础入门网络安全:学习路径与岗位方向解析
  • Python 标准库与生态应用指南:从入门到机器学习实战
  • Rust 异步 Web 框架 Axum 深入原理与高级用法
  • 企业为何强调建立标准操作流程 SOP
  • 电商 AI 绘画:产品提示词撰写实战指南
  • Linux 基础 IO:文件描述符、重定向与缓冲区原理
  • Android Studio JDK 与 SDK 配置指南
  • MATLAB 2025a 发布:深色模式与 Copilot 编程助手详解
  • Qt Creator 配置 GitHub Copilot AI 编程插件

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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