【C++进阶】01:概述

news/2024/4/24 22:33:28/文章来源:https://blog.csdn.net/weixin_49167174/article/details/130040495

概述


OVERVIEW

  • 概述
      • C++11新特性:
      • C++14新特性:
      • C++17新特性:
      • C++20新特性:
      • C++程序编译过程
      • C++内存模型
      • C++STL
        • 1.Queue&Stack
        • 2.String
        • 3.Map

C语言C++语言
面向过程编程
面向对象编程(类和对象)
泛型编程、元编程(模板)
函数式编程(Lambda)
STL(function、bind、thread、智能指针)
其他(左值与右值、深拷贝、移动构造、返回值优化)
异常处理
设计模式(创建型模式4种、结构型模式7种、行为型模式7种)

在这里插入图片描述

C++11新特性:

  1. auto关键字
  2. decltype关键字
  3. nullptr字面值
  4. constexpr关键字
  5. for (declaration : expression)
  6. Lambda表达式
  7. initializer_list(初始化列表)
  8. 标准库bind函数
  9. 智能指针shared_ptr, unique_ptr
  10. 右值引用&&(C++性能得到非常大的提升)
  11. STL容器std::array, std::forward_list, std::unordered_map, std::unordered_set

C++14新特性:

  1. 扩展了lambda表达式,增加泛型:支持auto
  2. 扩展了类型推导至任意函数:C11只支持lambda返回类型的auto
  3. 弃用关键字deprecated

C++17新特性:

  1. 扩展了constexpr至switch if等:C++11的constexpr函数只能包含一个表达式
  2. typename嵌套
  3. inline内联变量
  4. 模板参数推导
  5. 元组类std::tuple\std::pair实现两个元素的组合
  6. 类模板std::variant表示一个类型安全的联合体
  7. 引用包装器std::reference_wrapper
  8. 边长参数模板
  9. 结构化绑定(函数多值返回时用{}合成struct)
  10. 非类型模板参数可传入类的静态成员
  11. 在if和switch中可进行初始化
  12. 初始化(如struct)对象时可用花括号对其成员进行赋值
  13. 简化多层命名空间的写法
  14. lambda表达式可捕获*this的值,但this及其成员为只读
  15. 十六进制的单精度浮点数
  16. 继承与改写构造函数
  17. usingB1::B1;//表示继承B1的构造函数
  18. 当模板参数为非类型时,可用auto自动推导类型
  19. 判断有没有包含某文件__has_include

C++20新特性:

  1. concept用于声明具有特定约束条件的模板类型

    template<typename T> concept number = std::is_arithmetic<T>::value; //声明一个数值类型的concept

  2. 范围库Ranges Library

  3. 协程Coroutines

  4. 模块Modules

C++程序编译过程

在这里插入图片描述

  1. 预处理Preprocessing:将.cpp文件转化为.i文件,cpp -o test.i test.cppgcc -E test.c -o test.i

    预处理器把所有include的文件包括递归包含的文件内容,都展开到输出文件,并展开了所有的宏定义。

  2. 编译Compilation:将.cpp/.h文件转换成.s文件,cc test.i -o test.sgcc -S test.i -o test.x

    编译的过程将预处理的文件进行一系列的词法分析、语法分析、语义分析及优化成相应的汇编代码。这一步中一般会进行优化,比如去除没有用到的类的声明、循环语句的优化等。

  3. 汇编Assemble:将.s文件转化为.o文件,as -o test.o test.sgcc -c test.s -o test.o

    as汇编器会将汇编代码转换为机器指令,并以特定的二进制格式输出保存在目标文件中

  4. 链接Linking:将.o文件转换为可执行程序,ld test.o -o testgcc test.c

    ld链接器将程序的相关目标文件组合链接在一起,生成程序的可执行映像文件。要解决的问题是:可能调用了库函数、或者一个目标文件中调用了另外一个文件中的库函数,需要通过链接器建立对应的关系,使程序能够正常的执行。

补充:静态链接与动态链接

  • 静态链接:将源代码从静态链接库中拷贝到最终的可执行程序中,这样可能会导致最终的目标文件很大。
  • 动态链接:需要调用的库函数以动态链接库的形式存在,多个进程之间共享。而链接的时候只需要知道要调用的函数的位置即可。在程序执行时当需要调用某个动态链接库中的函数式,操作系统首先会查找所有正在运行的程序,看内存中是否已经有该库函数的拷贝了,如果有则多进程之间可以共享该拷贝,否则才会将其载入到该进行的虚拟内存中。

C++内存模型

C++程序内存分为5个区:堆、栈、静态全局区、常量区、代码区

在这里插入图片描述

  • 堆:new/malloc创建的内存,堆在内存中位于bss区和栈区之间,用于动态内存分配,一般由程序员分配和释放。
  • 栈:函数中的临时变量(局部变量)、函数的参数值,由编译器自动分配释放,
  • 全局区:声明变量既不在函数中也不再类中,分为未初始化和已初始化全局变量,存放静态数据、常量,程序结束后由系统释放。
  • 只读常量区:存放常量字符串,程序结束后由系统释放
  • 代码区:函数的定义、类定义、相关的程序逻辑(函数体的二进制代码)

补充:静态分配与动态分配

  • 静态分配:指发生在程序编译和链接的阶段
  • 动态分配:发生在程序的运行阶段

C++STL

如果对SLT不够熟练,在企业开发当中将会导致开发效率十分低,

1.Queue&Stack

#include<iostream>
#include<queue>
using namespace std;int main() {queue<int> q;q.push(1);q.push(2);q.push(3);cout << "front = " << q.front() << " back = " << q.back() << " size = " << q.size() << endl;q.pop();cout << "front = " << q.front() << " back = " << q.back() << " size = " << q.size() << endl;q.pop();cout << "front = " << q.front() << " back = " << q.back() << " size = " << q.size() << endl;q.pop();cout << "front = " << q.front() << " back = " << q.back() << " size = " << q.size() << endl;q.pop();return 0;
}

在这里插入图片描述

可以看到虽然队列中只push了3次元素,但是使用queue进行第4次pop时程序也没有报错提醒,并且back的值居然得到了结果。

#include<iostream>
#include<stack>
using namespace std;int main() {stack<int> s;s.push(1);s.push(2);s.push(3);cout << "top = " << s.top() << " size = " << s.size() << endl;s.pop();cout << "top = " << s.top() << " size = " << s.size() << endl;s.pop();cout << "top = " << s.top() << " size = " << s.size() << endl;s.pop();cout << "top = " << s.top() << " size = " << s.size() << endl;s.pop();return 0;
}

在这里插入图片描述

栈中只push了3次元素,使用stack进行第4次pop时程序直接给出了segmentfault错误。

  • 总结:在使用queue和stack等容器时,一定要做有效性的校验,否则拿到的数据可能会出错,或者直接导致segmentfault.
if (!q.empty()) cout << "front = " << q.front() << " back = " << q.back() << " size = " << q.size() << endl;
else cout << "queue is empty!" << endl;
if (!s.empty()) cout << "top = " << s.top() << " size = " << s.size() << endl;
else cout << "stack is empty!" << endl;

2.String

  1. str1 == str2调用的是str1的方法还是str2的方法?(运算符重载)

    答:理解为调用的是类对象str1的函数,而str2作为参数传入函数中,str1是一个this指针(this对象是str1)

  2. str1=“abcdefg”; str1[7]=‘K’;不报错,而str1[20]=‘K’;报错segmentation fault的原因?

    答:string对象会进行自动扩容1.5~2倍(编译器决定)

    #include<iostream>
    #include<string>
    using namespace std;int main() {string str1 = "helloworld";cout << "str1 = " << str1 << " size = " << str1.size() << endl;cout << "str1[0] = " << str1[0] << endl;cout << "str1[9] = " << str1[9] << endl;cout << "str1[10] = " << str1[10] << endl;cout << "str1[11] = " << str1[11] << endl;cout << "str1[12] = " << str1[12] << endl;cout << "str1[13] = " << str1[13] << endl;cout << "str1[20] = " << str1[20] << endl;cout << "str1[50] = " << str1[50] << endl;cout << "str1[120] = " << str1[120] << endl;int n = 1000;while (n--) str1 += "T";cout << "str1 = " << str1 << " size = " << str1.size() << endl;return 0;
    }
    

    在这里插入图片描述

  3. str1.length()与strlen(str1)的区别?

    答:strlen的时间复杂度为O(n),而string.length的时间复杂度为O(1),string类中存储着length的大小,strlen为遍历方式

    #include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;int main() {int n = 100000000;string s1;while (n--) s1 += 'T';long start = clock();int size = s1.size();cout << "c++ size = " << size << " time = " << clock() - start << endl;start = clock();size = strlen(s1.c_str());cout << "c size = " << size << " time = " << clock() - start << endl;return 0;
    }
    

    在这里插入图片描述

    很明显的计算时间的差异

  4. cout对字符串的输出结束判定是通过str.size()的,而不是像C语言一样通过字符串末尾的\0

  5. 直接使用 str[11] = T 等赋值操作无法像 += 操作一样新增string字符串内容并触发string.size的修改。

3.Map

Map头文件命名空间
hash_map<hash_map>/<ext/hash_map>__gnu_cxx;
unordered_map<unordered_map>std
  1. 映射过程是根据哈希函数进行映射的,结果是乱序的,hash_map底层是利用数组实现的,在数组上再挂在链表。

  2. 使用map时需要预先进行find查找,以免访问未分配空间造成size增加!

    #include<iostream>
    #include<unordered_map>
    using namespace std;int main() {unordered_map<string, int> hashmap;hashmap["abc"] = 1;hashmap["abcd"] = 2;hashmap["abcde"] = 3;hashmap.insert(pair<string, int>("adcdef", 4));cout << "size = " << hashmap.size() << endl;cout << "hashmap[\"hello\"] = " << hashmap["hello"] << endl;//访问非法空间则自动生成一个默认的类型cout << "size = " << hashmap.size() << endl;return 0;
    }
    

    在这里插入图片描述

    auto it = hashmap.find("hello");
    if (it != hashmap.end()) cout << "hashmap[\"hello\"] = " << hashmap["hello"] << endl;
    else cout << "hashmap[\"hello\"] is not exist!" << endl;
    
  3. 当map集合非常大时,使用swap方法比直接使用运算符重载的=进行赋值更快!

    swap方法将两个数据集进行对换,对换的过程中没有出现内存的拷贝,速度比使用重载的赋值运算符更快。

    #include<iostream>
    #include<map>
    using namespace std;int main() {map<int, int> mymap1;int n = 10000;while (n--) mymap1[n] = 2;//map集合的数据集非常大10000条数据unsigned long tick = clock();map<int, int> mymap2 = mymap1;cout << "time(operator) = " << clock() - tick << endl;//直接使用运算符重载时消耗的时间tick = clock();map<int, int> mymap3;mymap3.swap(mymap1);cout << "time(switch) = " << clock() - tick << endl;//使用switch方法对换数据消耗的时间return 0;
    }
    

    在这里插入图片描述

  4. 遍历hashmap

    int main() {unordered_map<string, int> hashmap;hashmap["abc"] = 1;hashmap["abcd"] = 2;hashmap["abcde"] = 3;hashmap.insert(pair<string, int>("adcdef", 4));cout << "size = " << hashmap.size() << endl;auto it = hashmap.find("hello");if (it != hashmap.end()) cout << "hashmap[\"hello\"] = " << hashmap["hello"] << endl;else cout << "hashmap[\"hello\"] is not exist!" << endl;for (auto it = hashmap.begin(); it != hashmap.end(); ++it) {cout << "key = " << it->first << "\tvalue = " << it->second << endl;}for (auto it : hashmap) {cout << "key = " << it.first << "\tvalue = " << it.second << endl;}return 0;
    }
    

    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之七大排序

数据结构之七大排序&#x1f506;排序的概念及其运用排序的概念常见的排序算法&#x1f506;插入排序直接插入排序希尔排序&#x1f506;选择排序直接选择排序堆排序&#x1f506;交换排序冒泡排序快排&#x1f506;归并排序&#x1f506;非比较排序&#x1f506;结语&#x1f…

十二、Pytorch复现Residual Block

一、Residual Network 论文出处&#xff1a;Deep Residual Learning for Image Recognition 其核心模块&#xff1a; 二、复现Residual Block 这里以两层卷积层为例进行设计复现 resnet可以很好的解决梯度消失问题 Residual Block大致要点&#xff1a; 样本x传入模型&…

下一个“AI王炸”,别只盯着OpenAI,DeepMind也在憋大招

过去几个月&#xff0c;OpenAI风头无两&#xff0c;各大科技公司争先恐后地跟进大语言模型&#xff08;LLM&#xff09;这一技术路线。对比之下&#xff0c;OpenAI的老对手DeepMind&#xff0c;显得有些低调和沉默。微软靠OpenAI打了一场胜仗&#xff0c;而谷歌推出的Bard翻了车…

5.5G,运营商能接受吗?

2月份&#xff0c;我在巴塞罗那参加MWC 2023时有个发现。欧洲通信设备商大多在宣传和讨论6G相关技术&#xff0c;中国通信设备商却在重点展示5.5G&#xff0c;或者叫做5G-Advanced。而全球各国的运营商则都普遍处在比较观望的状态里&#xff0c;两头考察&#xff0c;多样化尝试…

中间表示- 到达定义分析

基本概念 定义&#xff08;def&#xff09;&#xff1a;对变量的赋值 使用&#xff08;use&#xff09;&#xff1a;对变量值的读取 问题&#xff1a;能把上图中的y替换为3吗&#xff1f;如果能&#xff0c;这称之为“常量传播”优化。 该问题等价于&#xff0c;有哪些对变量y…

OPNET Modeler 例程——创建一个移动无线网络

文章目录一、例程概述二、创建天线模型三、创建指向处理器四、创建节点模型1.发射机节点模型2.干扰发射机节点模型3.收信机节点模型五、创建网络模型六、收集统计量并运行仿真七、查看仿真结果总结一、例程概述 OPNET 无线模块支持地面和卫星无线系统的构建。在此例程中将构建…

【C++】基础篇

C基础篇什么是C命名空间命名空间的三种使用方式C的输入和输出缺省参数缺省参数分类函数重载引用引用的使用场景常引用指针和引用的区别auto关键字auto使用细则auto不能推导的场景基于范围的for循环范围for的使用条件指针空值nullptr什么是C 1982年&#xff0c;Bjarne Stroustr…

微服务+springcloud+springcloud alibaba学习笔记【Eureka服务注册中心】(3/9)

Eureka服务注册中心 3/91、服务注册与发现1.1 什么是服务治理&#xff1a;1.2 什么是服务注册与发现&#xff1a;1.3 Eureka服务注册与发现2、单机版eureka2.1 创建module2.2改pom依赖2.3写yml配置文件:2.4主启动类2.5 修改服务提供者 cloud-provider-payment8001 模块&#xf…

GFS的卷类型与集群实验文档

GlusterFS 支持七种卷&#xff0c;即分布式卷、条带卷、复制卷、分布式条带卷、分布式复制卷、条带复制卷和分布式条带复制卷。我们常用的有前五种&#xff0c;今天我们就来看一看这五种卷都有什么优缺点。 一、分布式卷&#xff08;Distribute volume&#xff09; 文件通过 H…

【模型复现】resnet,使用net.add_module()的方法构建模型。小小的改进大大的影响,何大神思路很奇妙,基础很扎实

从经验来看&#xff0c;网络的深度对模型的性能至关重要&#xff0c;当增加网络层数后&#xff0c;网络可以进行更加复杂的特征模式的提取&#xff0c;所以当模型更深时理论上可以取得更好的结果。但是更深的网络其性能一定会更好吗&#xff1f;实验发现深度网络出现了退化问题…

python玄阶斗技--tkinter事件

在前一篇文章中&#xff0c;我们已经了解是tkinter的一些标签的使用&#xff0c;但一个GUI程序除了让别人看到&#xff0c;还要有一些交互操作&#xff0c;实现人机交互的方法我们称为事件&#xff0c;通过事件分为&#xff1a;鼠标事件&#xff0c;键盘事件和窗口事件。接下来…

Neo4j初学者使用记录(在更)

打开Neo4j cmdR 输入neo4j console 浏览器中输入框中网址&#xff1a;http://localhost:7474/即可打开 新建库 服务器版需要更改配置文件&#xff0c;若neo4j服务正在运行&#xff0c;则按Ctrlc&#xff0c;停止该服务。 配置完后&#xff0c;再重新开启服务&#xff0c;刷新…

如何利用ventoy制作Linux to go (把deepin放到U盘里)

准备工作 最新版本 – 深度科技社区 (deepin.org) deepin镜像官方下载即可 Releases ventoy/vtoyboot GitHub ventoy启动插件选择1.0.29版本 Downloads – Oracle VM VirtualBox VirtualBox虚拟机官网 ventoy下载 VentoyRelease (lanzoui.com) 选择下载1.0.29版本 vento…

第五十八章 线段树(一)

第五十八章 线段树&#xff08;一&#xff09;一、树状数组的缺陷二、线段树的作用三、线段树的基本构成1、节点定义2、线段树的结构四、线段树的重要函数1、构造线段树——bulid函数2、查询区间——query函数3、单点修改——modify函数五、例题一、树状数组的缺陷 在前面两个…

对于电商行业来讲,真正决定它的并不是规模,而是载体

纵然是在现在这样的情况之下&#xff0c;我们依然无法用「格局已定」来形容和阐述现在的电商市场格局。这一点&#xff0c;我们可以从以抖音、快手为代表的电商新势力的崛起当中&#xff0c;看出一丝端倪。对于电商行业来讲&#xff0c;真正决定它的并不是规模&#xff0c;而是…

Dart中的异步

一 事件循环 flutter 就是运行在一个root isolate 中 程序只要运行起来&#xff0c;就有一个事件循环一直在运行 &#xff0c;直至程序退出。 EventLoop 先从mrcro 对列中取任务&#xff0c;取完任务再去 event 队列中取任务。队列任务是FIFO。 二 认识Future abstract clas…

[JavaEE]----Spring03

文章目录Spring_day031&#xff0c;AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念2&#xff0c;AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知…

C++内存管理(new和delete)

目录 1. new/delete操作内置类型 2. new和delete操作自定义类型 3. operator new与operator delete函数 4 .new和delete的实现原理 1 .内置类型 2 .自定义类型 new的原理 delete的原理 new T[N]的原理 delete[]的原理 5. 定位new表达式(placement-new) 6. malloc/f…

使用Process Explorer和Clumsy定位软件高CPU占用问题

目录 1、问题描述 2、使用Process Explorer初步找到CPU占用高的原因 3、使用Clumsy工具在公司内网环境复现了问题 4、根据Process Explorer中的函数调用堆栈&#xff0c;分析源码&#xff0c;最终找出了问题 5、总结 在排查项目客户的视频图像闪烁问题时&#xff0c;无意中…

Centos7安装部署Jenkins

Jenkins简介&#xff1a; Jenkins只是一个平台&#xff0c;真正运作的都是插件。这就是jenkins流行的原因&#xff0c;因为jenkins什么插件都有 Hudson是Jenkins的前身&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控程序重复的工作&#xff0c;Hudson后来被…