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

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

C++11 引入多项关键特性提升开发效率与性能。涵盖可变参数模板与 emplace 系列接口,详解移动语义、默认成员函数控制及委托构造函数。重点分析 STL 容器变化与新接口应用,深入剖析 Lambda 表达式语法、捕获列表机制及其底层仿函数原理。结合完整代码示例,展示右值引用与完美转发在实际场景中的优化效果,帮助开发者掌握现代 C++ 编程核心能力。

小熊软糖发布于 2026/3/29更新于 2026/9/1269 浏览
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 还支持新玩法。假设容器为 container,emplace 还支持直接插入构造 T 对象的参数,这样有些场景会更高效一些,可以直接在容器空间上构造 T 对象。

emplace_back 总体而言是更高效,推荐以后使用 emplace 系列替代 insert 和 push 系列(也不是完全被淘汰了),只是说建议之后用 emplace_back 替代 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 还具有 typedef 没有的功能
    // 使用类型别名(C++11 新特性)
    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(), std::forward<Args>(args)...);
    }

    template<class... Args>
    void emplace(iterator pos, Args&&... args) {
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* newnode = new Node(std::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(), std::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(std::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 (auto 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:

更多推荐文章

查看全部
  • AI 时代为何选择 macOS:开发环境避坑指南
  • Python 爬虫实战:抓取微信公众号文章内容
  • SHA-256 哈希破解工具技术解析
  • Unity VR 眼镜端高分辨率全景视频播放性能优化
  • Whisper 语音识别本地化部署实战指南
  • C++ ODB 数据库 ORM 框架详解
  • 前端面试核心知识点梳理:JavaScript、框架与网络协议
  • Git 入门教程
  • 长亭雷池 WAF 部署与实战指南
  • 扩散模型原理与图像生成实战
  • Windows Git 安装与配置全流程指南
  • C/C++ 核心:函数指针与回调函数实战详解
  • VR/AR/MR 技术详解:虚实交互的区别与核心应用
  • AI 智能体十大企业盘点:金智维、腾讯云、蚂蚁数科技术解析
  • Spring Cloud 熔断降级详解:Sentinel 实战与原理类比
  • AI 短视频制作技术指南:文本、图片与视频生成
  • Vue 3 实战:10 个提升开发效率的常用技巧
  • 【大模型知识】Chroma + Ollama + Llama 3.1 搭建本地知识库
  • 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