c++11新增特性

news2025/1/16 1:00:25

目录

新增容器

​编辑

新增语法

变量类型推导

auto

存储类型

分类

自动存储类型

静态存储类型

寄存器存储类型

外部链接存储类型

decltype

typeid(c++98)

type_info

{ }初始化

initializer_list

介绍

使用

模拟实现

nullptr

final与override

范围for

右值引用

引入

介绍 

左值引用

右值引用 

纯右值

将亡值

move函数

用途

引入(左值引用返回的缺陷)

介绍

移动

介绍

移动构造函数 

使用

移动赋值函数 

使用


新增容器

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

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

新增语法

变量类型推导

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对象的引用,该对象包含有关表达式的类型信息
  • 头文件:<typeinfo>

  • type_info
  • 用于获取和比较对象的类型信息

{ }初始化

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

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

但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<int> vec = {1, 2, 3, 4};

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

initializer_list

介绍

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

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

使用

  • std::initializer_list作为参数的构造函数,方便初始化容器对象
  • 也可以作为operator=的参数,这样就可以用大括号赋值
  • auto il = { 10, 20, 30 };
    cout << typeid(il).name() << endl;

模拟实现

比如说,为vector增加初始化列表的构造和赋值重载

        myvector(initializer_list<T>& l)
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
        {
            reserve(l.size());

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

        myvector<T> &operator=(initializer_list<T>& l) // v传进来首先会进行拷贝构造,所以形参和实参空间不同
        {
            myvector<T> tmp(l);
            swap(tmp);
            return *this;
        }

这样它也能实现c++11新增的操作

nullptr

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

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

final与override

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

范围for

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

底层就是调用了迭代器

右值引用

引入

在之前,我们就已经接触了引用的概念,但c++进一步增加了右值引用的概念,所以之前使用的引用就被叫做左值引用了

但无论左值引用还是右值引用,都是给对象取别名,只不过对象类型不同

介绍 

左值引用
  • 左值是一个表示数据的表达式,我们可以获取它的地址+可以对它赋值
  • int* p = new int(0);
    int b = 1;
    const int c = 2;
  • 赋值符号左边只能是左值
  • 定义时const修饰符后的左值,既可以引用左值,也可以引用右值
  • 左值引用就是给左值的引用,给左值取别名
  • int*& rp = p;
    int& rb = b;
    const int& rc = c;
    int& pvalue = *p;
右值引用 
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,部分函数返回值等等

右值分为纯右值和将亡值(将亡值实际上也属于左值)

  • 纯右值
  • 是字面常量/表达式返回值/匿名的临时对象
  • double x = 1.1, y = 2.2;
    
    //下面都是右值
    10;
    x + y;
    fmin(x, y);
  • 将亡值
  • 当该右值完成初始化或赋值的任务时,它的资源已经移动给了被初始化者或被赋值者,同时该右值也将会马上被销毁
  • 右值可以出现在赋值符号的右边
  • 右值不能取地址,但给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址
  • 右值引用就是对右值的引用,给右值取别名
  • int&& rr1 = 10;
    double&& rr2 = x + y;
    double&& rr3 = fmin(x, y);
move函数
  • 是 C++ 标准库中的一个函数模板,用于将左值转换为右值引用
  • 所以右值引用也可以引用move后的左值

用途

引入(左值引用返回的缺陷)

既然c++11引入了右值引用,说明之前只有左值引用时存在一些缺陷

众所周知,用引用作为参数,可以减少拷贝次数,尤其是深拷贝,对需要深拷贝的提升的效率更大

但是,如果涉及到临时变量,是绝对不能使用左值引用的:

  • (在之前引用那里就有介绍过,不能传临时变量的引用作为返回值,也不能使用引用接收返回值)
  • 所以,一般这里,就不会使用传引用返回,而是传值返回,以及用值接收返回值
  • 但就又会出现拷贝的问题
  • 因为传参会先创建一个临时变量,再将临时变量拷贝给ret2,这就会出现2次深拷贝,代价很大
  • 当然,新一点的编译器会做出优化,会将返回值直接拷贝给接收变量,但依然会有1次深拷贝
介绍

但是,利用移动语义可以补上这块短板

移动语义的核心就是通过使用右值引用和移动构造函数来实现资源的有效转移

移动

介绍

在C++中,"移动" 是指将资源(如动态分配的内存、文件句柄、对象等)的所有权从一个对象转移到另一个对象,而不进行不必要的数据复制

移动构造函数 

接受一个右值引用参数,用于实现资源的移动

在移动构造函数内部,资源的所有权被转移到新对象,同时原对象进入有效但未定义的状态,以确保原对象不再持有资源,防止原对象被析构后出现问题

void swap(myvector<T> &v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }
myvector(myvector<T> &&v)
            : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
       {
            cout << "移动构造" << endl;
            swap(v);
       }

防止出现下面情况时,发生不必要的拷贝:

使用
bit::myvector<int> func_move()
{
    cout << "func_move" << endl;
    auto it = {1, 2, 3, 4};
    myvector<int> tmp(it);
    return tmp;
}
void test7()
{
    bit::myvector<int> s1(func_move());
}

  • 深拷贝是构造tmp时候的
  • 本身应该是先深拷贝一个临时对象
  • 然后这个临时对象作为函数返回值(它是将亡值,当这个返回值完成拷贝工作后,就没了),调用移动构造初始化ret1
  • 但编译器做出了优化,跳过那个中间状态,直接对str进行移动构造,也就是直接将str识别成将亡值
  • 将tmp的资源直接给s1,使tmp成为有效但未定义的状态,之后随着func_move的结束而销毁

移动赋值函数 

       myvector<T> &operator=(myvector<T>&& v)
        {
            cout << "移动赋值" << endl;
            swap(v);
            return *this;
        }

和移动拷贝非常像,都是转移资源

使用
bit::myvector<int> func_move()
{
    cout << "func_move" << endl;
    auto it = { 1, 2, 3, 4 };
    bit::myvector<int> tmp(it); //深拷贝
    return tmp; 
}

void test8() {
    bit::myvector<int> s2;
    s2 = func_move();
}

  • 这里因为s2的赋值和定义不在一行,所以没有优化
  • 因为要返回tmp赋值给s2,所以要先创建临时变量作为函数返回值
  • 但和上面一样,直接将tmp认为是将亡值,且有移动构造,所以使用移动构造构建临时对象
  • 然后将这个临时对象使用[=重载]赋值给s2
  • 而因为临时对象也是将亡值(匿名对象,且马上就要被销毁) ,且有移动赋值的存在,所以直接调用移动版本的,把临时对象的资源交给s2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PVIT:利用位置信息增强多模态模型理解用户意图的能力

论文链接&#xff1a; https://arxiv.org/abs/2308.13437 代码链接&#xff1a; https://github.com/PVIT-official/PVIT Demo&#xff1a; https://huggingface.co/spaces/PVIT/pvit 引言 随着ChatGPT等语言大模型的走红&#xff0c;越来越多人尝试探索为语言大模型赋予视觉能…

中断机制-通过AtomicBoolean实现线程中断停止

通过AutomicBoolean package com.nanjing.gulimall.zhouyimo.test;import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean;/*** author zhou* version 1.0* date 2023/10/15 2:42 下午*/ public class InterruptDemo2 {static AtomicBoole…

分治算法——快排 | 归并思想

文章目录 一、快排思想1. leetcode75. 颜色分类2. leetcode912. 排序数组3. leetcode215. 数组中的第K个最大元素4. leetcode面试题17.14. 最小K个数 二、归并思想1. leetcode912. 排序数组2. leetcodeLCR 170. 交易逆序对的总数3. 计算右侧小于当前元素的个数4. 翻转对 一、快…

GBJ3510-ASEMI电源控制柜专用GBJ3510

编辑&#xff1a;ll GBJ3510-ASEMI电源控制柜专用GBJ3510 型号&#xff1a;GBJ3510 品牌&#xff1a;ASEMI 芯片个数&#xff1a;4 封装&#xff1a;GBJ-4 恢复时间&#xff1a;&#xff1e;50ns 工作温度&#xff1a;-55C~150C 浪涌电流&#xff1a;350A 正向电流&am…

iWall:支持自定义的Mac动态壁纸软件

iWall Mac是一款动态壁纸软件&#xff0c;它可以使用任何格式的漂亮视频&#xff08;无须转换&#xff09;、图片、动画、Flash、gif、swf、程序、网页、网站做为您的动态壁纸、动态桌面&#xff0c;并且可以进行交互。 这款软件功能多、使用简单、体积小巧、不占用资源、运行…

Java每日笔试题错题分析(5)

Java每日笔试题错题分析&#xff08;5&#xff09; 一、错题知识点前瞻第1题第2题第3题第4题第5题第6题第7题 二、错题展示及其解析第1题第2题第3题第4题第5题第6题第7题 一、错题知识点前瞻 第1题 数组的初始化 数组的初始化有两种&#xff0c;分为静态初始化和动态初始化 静…

ai_drive67_基于不确定性的多视图决策融合

论文链接&#xff1a;https://openreview.net/forum?idOOsR8BzCnl5 https://arxiv.org/abs/2102.02051 代码链接&#xff1a;https://github.com/hanmenghan/TMC Zongbo Han, Changqing Zhang, Huazhu Fu, Joey Tianyi Zhou, Trusted Multi-View Classification, Internatio…

动态内存管理改造简易通讯录

动态通讯录 本章内容基于上章内容实现&#xff0c;具体情况若有不清楚&#xff0c;请先查看上一篇文章。 动态通讯录实现了&#xff0c;动态开辟&#xff0c;如果存放满了&#xff0c;再开辟空间进行存储&#xff0c;相对静态更方便一些。 动态通讯录需要改造的地方 我们基于…

Python--比较运算符

比较运算符 特别注意&#xff1a;当我们使用比较运算符对两个变量进行比较时&#xff0c;其返回一个布尔类型的值。 案例&#xff1a;两个数大小的比较 num1 10 num2 20 print(num1 > num2) # False print(num1 < num2) # True print(num1 > num2) # False print…

使用免费云服务器体验

免费的才是最贵的 谈谈使用【三*丰*云*免*费*服务器】的超级后悔体验 你以为开通了就永久免费了&#xff1f;怎么可能&#xff01;&#xff01;&#xff01; 使用方法 第一步&#xff1a;注册&#xff0c;实名认证 实名认证收费0.7 此时可以使用24小时&#xff0c;到期自动…

AI影像修复及图像超分辨率

AI图像修复软件主要包含人脸修复、图像超分等功能。人脸修复功能主要对图像上的人脸进行识别和修复&#xff0c;从模糊、缺损、噪声图像中恢复高质量人脸图像。图像超分功能主要对图像进行超分辨率重建&#xff0c;将低分辨率图像处理为高分辨率图像。 链接&#xff1a;https:…

Linux:基础命令

Linux&#xff1a;基础命令 0. Linux的目录结构1. Linux命令基础格式2. ls命令2.1 隐藏文件、文件夹 3. 相对和绝对路径3.1 特殊路径符 4. mkdir命令4.1 mkdir -p 选项 5. touch 创建文件6. cat命令 查看文件内容 0. Linux的目录结构 /&#xff0c;根目录是最顶级的目录了Linux…

【java学习—七】关键字super(32)

文章目录 1. 功能2. 代码中理解3. super调用父类构造器3.1. 结论一证明3.2. 结论二证明 4. this和super的区别 1. 功能 在 Java 类中使用 super 来调用父类中的指定操作&#xff1a; &#xff08;1&#xff09;super 可用于访问父类中定义的属性 &#xff08;2&#xff09;sup…

unity的脚本执行顺序问题

当一个物体同时挂载有多个脚本时&#xff0c;谁会先执行呢&#xff1f; 猜想&#xff1a;Test2在Test1的上面应该会先执行吧&#xff01; 结果&#xff1a;Test1先执行 如果你想要某一个脚本先执行&#xff0c;可以使用Awake方法 执行顺序 是先把所以脚本的Awake执行完&a…

【Transformer系列】深入浅出理解ViT(Vision Transformer)网络模型

一、参考资料 极智AI | 详解 ViT 算法实现 MobileViT模型简介 ECCV 2022丨力压苹果MobileViT&#xff0c;这个轻量级视觉模型新架构火了 ECCV 2022丨轻量级模型架构火了&#xff0c;力压苹果MobileViT&#xff08;附代码和论文下载&#xff09; 再读VIT&#xff0c;还有多少细…

学习笔记---超基础+详细+新手的顺序表~~

目录 1.顺序表的前言 1.1 顺序表--->通讯录&#x1f4c7; 1.2 数据结构的相关概念&#x1f3c7; 1.2.1 什么是数据结构 1.2.1 为什么需要数据结构 2. 顺序表概念及分类 2.1 顺序表的概念&#x1f419; 2.2 顺序表的分类&#x1f42b; 2.2.1 顺序表和数组的区别 2.…

c++ 学习之多态

来看代码 我们来看看早绑定的代码 #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Animal { public:void speak(){cout << "动物在说话 " << endl;} }; class Cat : public Animal { public:void speak() {cout…

android studio检测不到真机

我的情况是&#xff1a; 以前能检测到&#xff0c;有一天我使用无线调试&#xff0c;发现调试有问题&#xff0c;想改为USB调试&#xff0c;但是半天没反应&#xff0c;我就点了手机上的撤销USB调试授权&#xff0c;然后就G了。 解决办法&#xff1a; 我这个情况比较简单&…

LD链接脚本

1.LD链接脚本的简介 LD链接脚本的概念 LD链接器脚本在完整程序编译流程中的链接过程使用。LD链接器脚本定义了程序各个程序段的存储分布&#xff0c;描述链接器如何将这些目标文件.o文件链接成一个输出可执行文件LD链接器脚本与CPU的种类、MCU的内部存储器分布有关。 LD链接…

华为---企业WLAN组网基本配置示例---AC+AP组网

ACAP组网所需的物理条件 1、无线AP---收发无线信号&#xff1b; 2、无线控制器(AC)---用来控制管理多个AP&#xff1b; 3、PoE交换机---能给AP实现网络连接和供电的交换机&#xff1b; 4、授权&#xff1a;默认AC管理的AP数量有限&#xff0c;买授权才能管控更多AP。 WLAN创建…