C++学习:6补充

Posted 想文艺一点的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++学习:6补充相关的知识,希望对你有一定的参考价值。

C++11新特性


如何查看我们现在使用的是什么 C++ 标准


1、auto

  • 可以从初始化表达式中推断出变量的类型,大大简化编程工作
  • 属于编译器特性不影响最终的机器码质量不影响运行效率


2、decltype

  • 可以获取变量的类型


3、nullptr(null pointer:空指针)

  • 可以解决NULL的二义性问题

在 C++ 11 之前,NULL 既能代表指针、也可以代表整数 0 这样写代码会报错、

所以在 C++ 11 之后,我们使用 nullptr 来特指指针NULL 为整数 0.


4、快速遍历:

之前的数组遍历:

int array[] = {0,1,2,3,4,5};

int i = 0;
for(i=0;i<sizeof(array); i++){
    cout<< array[i] << endl;
}

C++ 11 之后的遍历:

  • 我们不需要理会数组的大小,编译器会挨个将元素赋值给 item 元素
int array[] = {0,1,2,3,4,5};

for(int item = array){     
    cout<< item << endl;
}

5、lambda表达式

lambda 表达式的结构很复杂,有很多种形式,它的本质就是一个函数

发明它的目的:为了将函数的作用域,放到函数体里面

(1)最简单的形式:[capture list] {function body} ,理解:

  • 这个是一个特殊的表达式,里面包含 捕获列表 + 函数实体
  • 它的本质就是一个函数

接下来给 lambda 表达式进行赋值

  • 函数实体既没有返回值,也没有函数实体。
  • 使用函数指针指向它。

更为简便的赋值

调用 lambda 函数实体


(2)添加函数的参数列表:[capture list] (params list) {function body}

  • 中间添加了参数列表,这个函数的参数列表


(3)添加函数的返回值:[capture list] (params list) -> return type {function body}

  • -> return type ,return type 为这个函数的返回值类型
  • 但是 -> return type 可以进行省略。


6、lambda 捕获变量

描述:

解决

也可以进行隐式捕获:(而且默认是 值捕获


注意点:

(1)默认都是 值捕获

(2)地址捕获 :将 a 的地址传递进来。


7、Lambda表达式 - mutable

问题描述:如果我们想在 lambda 表达式当中修改传进行来的变量值

(1)使用 地址捕获:

(2)使用 mutable

注意:

C++14

1、泛型 lambda


2、对捕获的变量进行初始化


C++17

1、可以进行初始化的if、 switch语句 、

  • 变量 a 只为 if else 服务
  • 变量 b 只为 switch 服务


其他的新的语法特性还没有流行起来。


异常

在编程当中我们经常遇到的错误类型:

  • 语法错误:编译器就会提示我们
  • 逻辑错误:是程序员自己留下的错误。
  • 异常:在程序运行当中可能出现,也可能不出现

比如说在程序在运行过程当中,内存空间不足

这个情况比较夸张,但是在实际开发的时候,肯定有可能出现。

  • 每个程序分别写自己的代码,申请的次数多了,肯定会造成内存不足。
  • 异常没有被处理,会导致程序终止 。


1、捕捉

使用 try 和 catch 指令:

1、将可能发生异常的代码,放到 try 里面去。

2、一旦发生异常,就会自动到对应的 catch 当中执行代码。

  • 从每次产生异常,都会执行 catch 当中的代码

改进:我们出现异常之后,break 跳出。


分析流程:

  • 如果没有 break ,在执行完循环之后,也会跳出循环。
  • 有 break 的话,发生异常之后立马会调出循环。


2、主动抛出

  • 上面的异常是系统自身抛出的异常

  • 有的时候,可能需要我们自己去主动抛出异常

举例:0 做被除数,我们要主动抛出异常


catch 和 throw 的捕捉类型必须匹配

总结:

1、将可能发生异常的代码,放到 try 里面去。

2、一旦发生异常,就会自动到对应的 catch 当中执行代码。


异常抛出的声明:


3、自定义异常类型

  • 通过类来定义异常

  • 通过面向对象的思想,这有什么优势呢?
  • 自己可以添加很多的与异常相关的成员函数。


4、标准异常


智能指针

传统指针存在的问题

  • 需要手动管理内存
  • 容易发生内存泄露(忘记释放、出现异常等)
  • 释放之后产生野指针

内存泄漏:该释放内存的时候,没有释放,造成内存越来越少

指针的释放必须放到最后,并且还得赋值为 nullptr ,防止野指针

智能指针就不需要这么做

  • auto_ptr 是一个模板类,需要传入指向的对象类型
  • p 是一个对象,相当于将 newPerson()的返回值传给 p 的构造函数
  • p 在栈空间,当 test( ) 执行完毕之后,p就会被释放,然后堆空间的内容也会跟着释放。

注意:

  • 智能指针发明的目的:在栈空间的指针销毁时,将堆空间的内存进行释放。

  • 智能指针必须指向堆空间的对象,因为栈空间的对象不需要我们智能指针进行释放,系统会自动释放。

  • 如果指向栈空间的对象,那么就会造成二次释放


智能指针就是为了解决传统指针存在的问题

  • auto_ptr:属于C++98标准,在C++11中已经不推荐使用(有缺陷,比如不能用于数组)
  • shared_ptr:属于C++11标准
  • unique_ptr:属于C++11标准

1、自己实现智能指针

目的:在自己销毁的时候,释放堆空间。

初步实现:

缺点:

  • p1 并不是指针,而是一个对象,真正的指针是 m_pointer 成员变量。
  • 所以很不方便。

改进:将运算符进行重载

存在的问题:不能存放数组

  • 不能释放全部元素

改进:


2、shared_ptr

hared_ptr 的设计理念:

1、多个shared_ptr可以指向同一个对象,当最后一个shared_ptr在作用域范围内结束时,对象才会被自动释放。

可以通过一个已存在的智能指针初始化一个新的智能指针

  • p1 、 p2、p3、p4 都销毁的时候, new 的Person 内存才能够进行释放。


2、针对数组的用法


3、一个shared_ptr会对一个对象产生强引用(strong reference)

  • 每个对象都有个与之对应的强引用计数,记录着当前对象被多少个shared_ptr强引用着
  • 可以通过shared_ptr的 use_count 函数获得强引用计数
  • 当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
  • 当有一个shared_ptr销毁时(比如作用域结束),对象的强引用计数就会-1
  • 当一个对象的强引用计数为0时(没有任何shared_ptr指向对象时),对象就会自动销毁(析构)

多一个指向,强引用个数就会 + 1.少一个,就会减一

两次释放的情况


4、shared_ptr的循环引用

会导致内存泄漏:

  • Person 类当中有一个Car 类型的智能指针, m_car (成员变量

  • Car 类当中有一个 Person 类型的智能指针, m_person (成员变量

  • 在主函数,栈空间当中创建两个对象,Person 对象 ,Car 对象。

没有循环调用的情况:


有循环调用的情况:(你中有我,我中有你)

  • 缺点:内存泄漏,堆空间无法释放

内存分布图:

  • Person 对象当中的 m_car 指向 Car

  • Car 对象当中的 m_person 指向 Person

  • Car 和 Person 的强引用计数都是 2

  • 当栈空间释放之后,
  • Car 和 Person 的强引用计数都是 1 ,因为还有强引用计数的存在,所以堆空间不会销毁
  • shared_ptr 会产生强引用,只要有一个引用没有释放,那么就不会销毁堆空间

解决办法:使用弱引用 weak_ptr


3、weak_ptr

  • weak_ptr会对一个对象产生弱引用
  • weak_ptr可以指向对象,解决shared_ptr的循环引用问题

内存空间:


4、unique_ptr

  • unique_ptr也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象
  • 当unique_ptr 销毁时(作用域结束时),其指向的对象也就自动销毁了
  • 可以使用std::move函数转移unique_ptr的所有权

了解即可

以上是关于C++学习:6补充的主要内容,如果未能解决你的问题,请参考以下文章

VSCode 配置 用户自定义代码片段 自定义自动代码补充

C++ 解释器/控制台/片段编译器

这些 C++ 代码片段有啥作用?

有趣的 C++ 代码片段,有啥解释吗? [复制]

以下代码片段 C++ 的说明

C++ 代码片段执行