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


在这里插入图片描述

个人主页艾莉丝努力练剑

专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平

艾莉丝的简介:

在这里插入图片描述


艾莉丝的C++专栏简介:

在这里插入图片描述



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容器新增了empalce系列的接口,empalce系列的接口均为模板可变参数,功能上兼容push和insert系列,但是empalce还支持新玩法,假设容器为container,empalce还支持直接插入构造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的构造,所以达到了前面说的empalce支持直接插入构造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 成员函数声明时要给缺省值

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

往期回顾:【类和对象(下)】C++类与对象的进阶艺术:初始化列表到性能优化的完全指南
在这里插入图片描述

5.3 defult和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 最佳实践

这两个函数了解即可,艾莉丝给uu们简单演示了一下——
在这里插入图片描述

5.5 final和override

老朋友,这个final和override我们在继承和多态那个章节已经进行了详细讲过了,uu们如果忘了就看一下艾莉丝往期的博客——

【C++:继承】C++面向对象继承全面解析:派生类构造、多继承、菱形虚拟继承与设计模式实践

在这里插入图片描述

【C++:多态】C++多态实现深度剖析:从抽象类约束到虚函数表机制

在这里插入图片描述

这里艾莉丝重新展示一下关于final和override艾莉丝画的思维导图——
在这里插入图片描述


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

6.1 新的容器

下面这张图中圈起来的就是 C++11的STL中的新增容器,但是实际中最有用的是**unordered_map和unordered_set**。

C++11新增容器:array、forward_list(单链表)、unordered_map和unordered_ed(真正有用的就这俩)——
在这里插入图片描述

这两个我们前面已经进行了非常详细的介绍,其他的大家了解一下即可,艾莉丝这里再把介绍两个容器的博客链接放在这里——

【C++:unordered_set和unordered_map】C++无序容器深度解析:unordered_set和unordered_map的使用

6.2 新的接口

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

6.3 宝藏:范围for

容器的范围for遍历,这个在容器部分也讲过了,这里艾莉丝把链接挂在下面了——

【C++:map和set的使用】C++ map/multimap完全指南:从红黑树原理入门到高频算法实战

在这里插入图片描述


7 ~> lambta

7.1 lambta表达式的语法

在这里插入图片描述

7.1.1 概念

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

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

lambda表达式的格式:

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

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

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

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

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

在这里插入图片描述

7.1.2 最佳实践

在这里插入图片描述

7.2 lambta的应用场景

7.2.1 说明

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

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

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 lambta的原理

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还具有tepedef没有的功能
        // 使用类型别名(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;
            }
            // operator*()返回对应数据类型的引用
            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>
              //struct list_const_literator
              //{
              //	using Self = list_const_literator<T>;
              //	using Node = list_node<T>; Node* _node;
              //	Node* _node;
              //	list_const_iterator(Node* node)
              //		:_node(node)
              //	{ }
              //	// *it
              //	const T& operator*()
              //	{
              //		return _node->_data;;
              //	}
              //	// ++it
              //	Self& operator++()
              //	{
              //		_node = _node->_next;
              //		return *this;
              //	}
              //	Self operator++(int)
              //	{
              //		Self tmp(*this);
              //		_node = _node->_next;
              //		return *this;
              //	}
              //	// --it
              //	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*>; // 常量迭代器
                  // const T* 只能读数据,不能修改数据
                  //using iterator = list_iterator<T>;
                  //using const_iterator = list_const_iterator<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;
                          }
                          ////------------现代写法------------
                          //list(list<T>& lt)
                          //	list(const list& lt)
                          //{
                          //	empty_init();
                          //	list tmp(lt.begin(), lt.end());
                          //	swap(tmp);
                          //}
                          //// lt1 = lt3
                          ////list<T>& operator=(list<T> tmp)
                          //list& operator=(list tmp)
                          //{
                          //	swap(tmp);
                          //}
                          // ----------------容量操作---------------
                          // 交换两个链表的内容
                          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("111111111111");
                //	cout << "**************************" << endl;
                //
                //	lt.emplace_back("111111111111");
                //	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", 1);
                            //	//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;
                                    }

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝再次感谢您的阅读!

结语:希望对学习C++相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

往期回顾

博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

在这里插入图片描述

posted @ 2026-01-21 11:31  clnchanpin  阅读(1)  评论(0)    收藏  举报