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

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

C++11 新特性深度解析:从可变参数模板到 Lambda 表达式。本文涵盖可变参数模板与 emplace 系列接口的高效构造原理,详解移动语义、默认成员函数控制及委托构造函数机制。同时梳理 STL 新增容器与范围 for 遍历,深入剖析 Lambda 表达式的语法结构、捕获列表策略及其底层仿函数实现原理。结合完整代码示例,展示右值引用在容器插入与对象管理中的实际应用。

涅槃凤凰发布于 2026/3/29更新于 2026/7/2267 浏览
C++11 新特性深度解析:从可变参数模板到 Lambda 表达式

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

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

该文档在 C++98、C++11 时期尚可,之后版本更新滞后。

准官方文档(同步更新): cppreference

推荐作为主要查阅资源,涵盖至 C++26 标准,语法查询准确。

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

社区讨论活跃,适合深入探讨标准细节。


4. 可变参数模版

4.1 emplace 系列接口

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

STL 容器普遍支持 emplace_back 和 emplace 接口,用于原地构造元素。

4.1.2 emplace 系列接口概念
template<class... Args>
void emplace_back(Args&&... args);

template<class... Args>
iterator emplace(const_iterator position, Args&&... args);

C++11 引入的 emplace 系列接口基于模板可变参数,功能兼容 push 和 insert,但支持直接传递构造参数。相比 push_back 或 insert,emplace 能在容器内部空间直接构造对象,避免临时对象的拷贝或移动开销。

总体而言,emplace_back 效率更高,建议优先使用。当传入右值时,emplace_back 与 push_back 效率相近;但在处理 string 等复杂类型时,emplace_back 能一步到位直接构造,而 push_back 可能涉及额外的移动构造步骤。

模拟实现中,通过完美转发将参数包传递给节点构造函数,确保在容器存储位置直接完成 T 对象的构建。

4.1.3 万能引用

在参数包传递过程中,若使用 Args&&... args,需配合 std::forward<Args>(args) 进行完美转发,防止右值引用变量在展开后变为左值。


5. 新的类功能

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

C++ 类原本包含 6 个默认成员函数,C++11 新增了两个:移动构造函数和移动赋值运算符重载。

生成条件较为苛刻:若未自定义移动构造函数,且未定义析构函数、拷贝构造函数、拷贝赋值运算符中的任意一个,编译器会自动生成默认移动构造。对于内置类型执行逐字节拷贝,自定义类型则调用其移动构造(若存在),否则回退到拷贝构造。

注意:若提供了移动构造或移动赋值,编译器将不再自动生成拷贝构造和拷贝赋值。

5.2 成员函数声明时的缺省值

成员变量声明时的缺省值会在构造函数初始化阶段生效。若初始化列表中未显式指定,则使用声明时的缺省值;若显式指定,则以初始化列表为准。

5.3 default 和 delete

5.3.1 概念

C++11 允许更精细地控制默认函数的生成。若因定义了其他函数导致某些默认函数未生成(如定义了拷贝构造则不再生成移动构造),可使用 = default 显式请求生成。

若希望禁止某些函数被调用,C++98 需将其设为私有且不实现,C++11 则直接使用 = delete 标记为删除函数,编译期报错。

5.3.2 最佳实践

合理使用 default 和 delete 可明确表达设计意图,防止隐式行为带来的风险。

5.4 目标构造函数和委托构造函数

了解即可。目标构造函数指基类构造函数,委托构造函数指本类构造函数调用同类其他构造函数。二者有助于减少代码重复。

5.5 final 和 override

这两个关键字用于继承体系中的多态控制。

  • override:强制派生类虚函数重写基类虚函数,若签名不匹配则编译报错。
  • final:阻止后续类进一步重写当前虚函数或继承当前类。

6. C++11:STL 的变化

6.1 新的容器

C++11 新增了 array、forward_list、unordered_map 和 unordered_set。其中真正高频使用的是无序关联容器 unordered_map 和 unordered_set。

6.2 新的接口

重点在于右值引用和移动语义相关的插入接口(push/insert/emplace)、移动构造/赋值以及 initializer_list 版本的构造器。其他如 cbegin/cend 等辅助接口按需查阅文档即可。

6.3 范围 for

范围 for 遍历简化了容器迭代写法,底层依赖迭代器实现,是 STL 交互的重要基础。


7. Lambda 表达式

7.1 Lambda 表达式的语法

Lambda 本质是匿名函数对象,可定义在函数内部。由于没有具体类型名,通常使用 auto 接收。

格式如下:

[capture-list](parameters)->return type { function body }
  • capture-list:捕捉列表,决定外部变量的访问方式(传值/传引用)。不能省略。
  • parameters:参数列表,若无参可连同括号省略。
  • ->return type:返回值类型,可省略由编译器推导。
  • function body:函数体,不可省略。

7.2 Lambda 的应用场景

相比函数指针和仿函数,Lambda 定义更简洁。适用于线程执行逻辑、智能指针定制删除器等场景。

例如在排序操作中,无需额外定义仿函数结构体,直接在 sort 中嵌入 Lambda 即可完成比较逻辑。

7.3 捕捉列表

7.3.1 概念

Lambda 默认只能访问自身参数和局部变量。访问外层变量需显式或隐式捕捉。

  1. 显式捕捉:[x, y, &z] 表示 x、y 传值,z 传引用。
  2. 隐式捕捉:[=] 隐式传值,[&] 隐式传引用。编译器自动识别使用的变量。
  3. 混合捕捉:[=, &x] 其余传值,x 传引用。首元素必须是 = 或 &。

默认情况下,传值捕捉的对象是 const 的。添加 mutable 修饰符后可修改副本,但不影响实参。

注意:静态局部变量和全局变量无需捕捉,可直接访问。

7.4 Lambda 的原理

Lambda 底层是编译器生成的仿函数类。不同的 Lambda 对应不同的类名,参数、返回类型和函数体映射到仿函数的 operator()。捕捉列表变量成为仿函数类的成员变量,通过构造函数初始化。


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) {}
    };

    // --------------链表迭代器--------------
    template<class T, class Ref, class Ptr>
    struct list_iterator {
        using Self = list_iterator<T, Ref, Ptr>;
        using Node = list_node<T>;
        Node* _node;

        list_iterator(Node* node) : _node(node) {}

        Ref operator*() { return _node->_data; }
        Ptr operator->() { return &_node->_data; }

        Self& operator++() {
            _node = _node->_next;
            return *this;
        }
        Self operator++(int) {
            Self tmp(*this);
            _node = _node->_next;
            return tmp;
        }
        Self& operator--() {
            _node = _node->_prev;
            return *this;
        }
        Self operator--(int) {
            Self tmp(*this);
            _node = _node->_prev;
            return tmp;
        }

        bool operator!=(const Self& s) const { return _node != s._node; }
        bool operator==(const Self& s) const { 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*>;

        iterator begin() { return iterator(_head->_next); }
        iterator end() { return iterator(_head); }
        const_iterator begin() const { return const_iterator(_head->_next); }
        const_iterator end() const { return const_iterator(_head); }

        void empty_init() {
            _head = new Node;
            _head->_next = _head;
            _head->_prev = _head;
        }

        list() { empty_init(); }

        list(initializer_list<T> il) {
            empty_init();
            for (auto& e : il) push_back(e);
        }

        template<class InputIterator>
        list(InputIterator first, InputIterator last) {
            empty_init();
            while (first != last) {
                push_back(*first);
                ++first;
            }
        }

        list(size_t n, T val = T()) {
            empty_init();
            for (size_t i = 0; i < n; ++i) push_back(val);
        }

        ~list() {
            clear();
            delete _head;
            _head = nullptr;
            _size = 0;
        }

        void swap(list<T>& 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(), 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->_next = newnode;
            newnode->_prev = prev;
            newnode->_next = cur;
            cur->_prev = newnode;
            ++_size;
        }

        void push_back(T&& x) {
            insert(end(), forward<T>(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) {
            Node* cur = pos._node;
            Node* prev = cur->_prev;
            Node* newnode = new Node(x);
            prev->_next = newnode;
            newnode->_prev = prev;
            newnode->_next = cur;
            cur->_prev = newnode;
            ++_size;
        }

        void insert(iterator pos, T&& x) {
            Node* cur = pos._node;
            Node* prev = cur->_prev;
            Node* newnode = new Node(move(x));
            prev->_next = newnode;
            newnode->_prev = prev;
            newnode->_next = cur;
            cur->_prev = newnode;
            ++_size;
        }

        iterator erase(iterator pos) {
            Node* cur = pos._node;
            Node* prev = cur->_prev;
            Node* next = cur->_next;
            prev->_next = next;
            next->_prev = prev;
            delete cur;
            --_size;
            return next;
        }

        size_t size() const { 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>
#include <algorithm>
#include <assert.h>

using namespace std;

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);
        }

        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() {
            delete[] _str;
            _str = nullptr;
        }

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

        void reserve(size_t new_capacity) {
            if (new_capacity > _capacity) {
                char* tmp = new char[new_capacity + 1];
                if (_str) strcpy(tmp, _str);
                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;
    };
}

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

struct Goods {
    string _name;
    double _price;
    int _evaluate;

    Goods(const char* str, double price, int evaluate)
        : _name(str), _price(price), _evaluate(evaluate) {}
};

int main() {
    // emplace_back 测试
    list<Alice::string> lt;
    lt.emplace_back("111111111111111111");

    // 日期类测试
    list<Date> lt_date;
    lt_date.emplace_back(2025, 11, 18);

    // Lambda 排序测试
    vector<Goods> v = {
        {"苹果", 2.1, 5},
        {"香蕉", 3, 4},
        {"橙子", 2.2, 3},
        {"菠萝", 1.5, 4}
    };

    sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) {
        return gl._price < gr._price;
    });

    // Lambda 捕获测试
    int a = 0, b = 1;
    auto func1 = [a, &b]() mutable {
        int ret = a + b;
        b++;
        return ret;
    };
    cout << func1() << endl;

    return 0;
}

目录

  1. C++ 学习阶段的三个参考文档
  2. 4. 可变参数模版
  3. 4.1 emplace 系列接口
  4. 4.1.1 不同容器 emplace 系列接口展示
  5. 4.1.2 emplace 系列接口概念
  6. 4.1.3 万能引用
  7. 5. 新的类功能
  8. 5.1 默认成员函数:移动构造和移动赋值
  9. 5.2 成员函数声明时的缺省值
  10. 5.3 default 和 delete
  11. 5.3.1 概念
  12. 5.3.2 最佳实践
  13. 5.4 目标构造函数和委托构造函数
  14. 5.5 final 和 override
  15. 6. C++11:STL 的变化
  16. 6.1 新的容器
  17. 6.2 新的接口
  18. 6.3 范围 for
  19. 7. Lambda 表达式
  20. 7.1 Lambda 表达式的语法
  21. 7.2 Lambda 的应用场景
  22. 7.3 捕捉列表
  23. 7.3.1 概念
  24. 7.4 Lambda 的原理
  25. C++11 完整代码示例与实践演示
  26. list.h
  27. Test.cpp
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 前缀和技术实战:从乘积到整除子数组
  • JavaShop 百万级并发场景下的性能表现与架构解析
  • Z-Image i2L 本地 AI 绘画工具快速入门与参数调优
  • OpenClaw 爆红启示:AI 助手如何改写开源规则
  • 66 个 Java 常见代码示例:从基础语法到并发编程
  • MCP 协议详解:与 Function Call 的区别及使用思路
  • 黑客与程序员的思维差异及技能对比
  • 基于 Maven + Docker 的 WebApp 打包与部署
  • Stable Diffusion XL 1.0 灵感画廊镜像免配置部署指南
  • Qwen-Image-Lightning 极速图像生成技术解析
  • AI 写论文提示词指令大全
  • Java 时间类(中):JDK8 全新时间 API 详细教程
  • Python 网络编程:TCP 与 UDP 的区别详解
  • AI 产品经理面试核心考点与实战指南
  • 用 LLaMA-Factory WebUI 微调 Qwen2.5-VL
  • HarmonyOS RcTag 组件实战:技能标签墙与搜索热词
  • 基于 VoxCPM-1.5-TTS 实现配置文件差异语音提醒方案
  • 2026 年 AI 编程助手组合使用心得
  • 《AI 赋能:AI 重新定义产品经理》书籍核心内容梳理
  • Protobuf C++ 实战入门指南

相关免费在线工具

  • 加密/解密文本

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