c++11新增特性

目录

新增容器

​编辑

新增语法

变量类型推导

auto

存储类型

分类

自动存储类型

静态存储类型

寄存器存储类型

外部链接存储类型

decltype

typeid(c++98)

type_info

{ }初始化

initializer_list

介绍

使用

模拟实现

为什么是值传参呢?

nullptr

final与override

范围for


新增容器

c++11新增特性_第1张图片

框起来的都是c++11中新增的容器

  • 其中哈希系列的set和map都很有用
  • array对标的是静态数组,但是比起来只是多了个下标检测,很鸡肋
  • forward_list其实就是单链表,但也没啥用,指定位置的插入/删除都只能操作给定位置的后一个结点
  • c++11新增特性_第2张图片

新增语法

变量类型推导

auto

c++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型
存储类型

用来描述变量的存储、生命周期和作用域的属性

分类

自动存储类型,静态存储类型,寄存器存储类型和外部链接存储类型

自动存储类型
  • 局部变量的默认存储类别
  • 这些变量在函数或块内部声明,它们的生命周期与包含它们的函数或块的执行周期相关联
  • 当函数或块退出时,自动存储变量会被销毁
静态存储类型
  • 在程序的生命周期内都存在,而不仅仅在其声明的作用域内
  • 它们只被初始化一次
寄存器存储类型
  • 用于请求编译器将变量存储在CPU的寄存器中,以加速对其的访问
  • 关键字是register
  • 现代编译器通常会智能地管理寄存器,所以这个类型一般不再使用了
外部链接存储类型
  • 这些变量可以在不同的文件中访问,它们通常被用于全局变量,以在不同的源文件之间共享数据
  • 关键字是extern

但是 [局部域中定义局部的变量] 默认就是自动存储类型,所以auto就没啥用了

c++11对auto进行了改变,让他可以根据初始化值的类型自动推导变量类型

注意:auto仅能通过初始值推导类型,而不能直接作为类型定义对象,所以传参/没有初始值的情况下,不能使用auto

decltype

delcltype的用处就体现了出来,auto不能做的,他可以做

他可以根据[decltype( 变量 )中变量的类型]作为一种类型,来声明/定义变量

int main()
{
    const int x = 1;
    double y = 2.2;
    decltype(x * y) ret; // ret的类型是double
    decltype(&x) p;      // p的类型是int*
    return 0;
}

typeid(c++98)

  • typeid是c++98引入的,但鉴于这里都是讲类型的,所以也介绍一下

  • 它可以用来确定一个对象或表达式的实际运行时类型
  • typeid返回一个type_info对象的引用,该对象包含有关表达式的类型信息
  • 头文件:

  • type_info
  • 用于获取和比较对象的类型信息
  • c++11新增特性_第3张图片

{ }初始化

也被称为统一初始化/列表初始化

原先,只有数组可以使用{ }进行初始化

但c++11进行了扩展,让所有的内置类型和自定义的类型都可以使用{ }进行初始化 :

int x = {42};
double y{3.14}; //加不加=都可以

int arr[] = {1, 2, 3, 4};

struct Point {
    int x;
    int y;
};
Point p = {10, 20};

int* pa = new int[4]{ 0 };

//定义自定义对象,会调用其构造函数
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };

上面除了数组外,传入的都是[构造函数参数]个数的参数,也就是每次插入一个元素

而{ }初始化通过某个新类的支持,可以实现下面的操作(传入多个元素到容器中):

std::vector vec = {1, 2, 3, 4};

而这个新类就是下面要介绍的initializer_list

initializer_list

介绍

是 C++11 标准引入的一种容器,用于初始化容器类对象或用户自定义类型的对象

允许以初始化列表的形式传递多个值给对象的构造函数

使用

  • std::initializer_list作为参数的构造函数,方便初始化容器对象
  • c++11新增特性_第4张图片
  • 也可以作为operator=的参数,这样就可以用大括号赋值
  • c++11新增特性_第5张图片
  • auto il = { 10, 20, 30 };
    cout << typeid(il).name() << endl;
  • c++11新增特性_第6张图片

模拟实现

比如说,为之前模拟实现过的vector增加初始化列表的构造和赋值重载

        /*myvector(const initializer_list &l)  //初始化列表构造(传入引用)
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
        {
            cout << "深拷贝" << endl;
            reserve(l.size());

            for (auto &it : l)
            {
                push_back(it);
            }
        }*/
        myvector(initializer_list l) // 初始化列表构造
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
        {
            //cout << "深拷贝" << endl;
            reserve(l.size());

            for (auto &it : l)
            {
                push_back(it);
            }
        } 


        /*myvector &operator=(const initializer_list &l) // 初始化列表赋值(传入引用)
        {
            cout << "深拷贝" << endl;
            myvector tmp(l);
            swap(tmp);
            return *this;
        }*/
        myvector &operator=(initializer_list l) // 初始化列表赋值
        {
            cout << "深拷贝" << endl;
            myvector tmp(l);
            swap(tmp);
            return *this;
        }

可以是引用,也可以是传值

但我们会发现,库里的都是值传参

为什么是值传参呢?

一般我们使用的时候,都是这么写的:

 myvector s2 = {1, 2, 3, 4};

这里会发生隐式类型转换,生成一个右值

  • 如果直接写一个右值引用的参数,万一这个initializer_list是左值,就不方便了
  • 所以可以写成const左值引用
  • 但是可能会出现"悬挂引用"的问题(就是引用的对象已经销毁了)
  • 所以,为了安全性,值传参是最好的选择

nullptr

是 c++11 标准引入的关键字,用于表示空指针

  • 在之前都是用NULL来表示空指针,但在之前,NULL在c++实际上是整型值0
  • c++11新增特性_第7张图片
  • 普通使用的时候,确实可以正常的被类型转换
  • 但如果遇到函数重载(一个是指针类型,一个是int类型),传入NULL的话,就会匹配int那个函数,不符合我们的预期
  • 所以c++11引入了一个新的关键字

final与override

这两个关键字实际上在多态那里已经介绍过了

c++11新增特性_第8张图片

c++11新增特性_第9张图片

范围for

范围for我们都快用烂了,非常好用的一个语法糖

底层就是调用了迭代器

 

除了这些之外,还有右值引用+移动语义,智能指针,lambda表达式,成员函数控制,可变参数模板,适配器,线程库,将在之后一一介绍

 

你可能感兴趣的:(c++,c++)