【图解八股-C/C++④-C++新特性】

作者简介和专栏内容见专栏介绍:https://www.nowcoder.com/creation/manager/columnDetail/0eL5bM

麻烦看到贴子的伙伴点点赞大家点赞订阅支持下,提前祝各位offer多多,有问题评论区见~~

图解版

C++新特性

C++ 11有哪些新特性?

  • nullptr替代 NULL
  • 引入了 auto 和 decltype 这两个关键字实现了类型推导
  • 基于范围的 for 循环for(auto& i : res){}
  • 类和结构体的中初始化列表
  • Lambda 表达式(匿名函数)
  • std::forward_list(单向链表)
  • 右值引用和move语义

auto、decltype和decltype(auto)的用法

(1)auto

C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应某种特定的类型说明符(例如 int)不同,auto 让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说 auto 定义的变量必须有初始值。

(2)decltype

有的时候我们还会遇到这种情况,我们希望从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的值类型。在这些时候auto显得就无力了,所以C++11又引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器只是分析表达式并得到它的类型,却不进行实际的计算表达式的值。

C++中NULL和nullptr区别

比如有两个重载的函数u,一个接收int, 一个接收指针。但是NULL本来想当做指针的,但是处理成0

NULL来自C语言,一般由宏定义实现,而 nullptr 则是C++11的新增关键字。在C语言中,NULL被定义为(void*)0,而在C++语言中,NULL则被定义为整数0

在C++中指针必须有明确的类型定义。但是将NULL定义为0带来的另一个问题是无法与整数的0区分。因为C++中允许有函数重载。那么在传入NULL参数时,会把NULL当做整数0来看,如果我们想调用参数是指针的函数,该怎么办呢?nullptr在C++11被引入用于解决这一问题,nullptr可以明确区分整型和指针类型,能够根据环境自动转换成相应的指针类型,但不会被转换为任何整型,所以不会造成参数传递错误。

智能指针的原理、常用的智能指针及实现

原理

智能指针是一个类,用来存储指向动态分配对象的指针,负责自动释放动态分配的对象,防止堆内存泄漏。动态分配的资源,交给一个类对象去管理,当类对象声明周期结束时,自动调用析构函数释放资源

常用的智能指针

(1) shared_ptr

实现原理:采用引用计数器的方法,允许多个智能指针指向同一个对象,每当多一个指针指向该对象时,指向该对象的所有智能指针内部的引用计数加1,每当减少一个智能指针指向对象时,引用计数会减1,当计数为0的时候会自动的释放动态分配的资源。

  • 智能指针将一个计数器与类指向的对象相关联,引用计数器跟踪共有多少个类对象共享同一指针
  • 每次创建类的新对象时,初始化指针并将引用计数置为1
  • 当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数
  • 对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数
  • 调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)

(2) unique_ptr

unique_ptr采用的是独享所有权语义,一个非空的unique_ptr总是拥有它所指向的资源。转移一个unique_ptr将会把所有权全部从源指针转移给目标指针,源指针被置空;所以unique_ptr不支持普通的拷贝和赋值操作,不能用在STL标准容器中;局部变量的返回值除外(因为编译器知道要返回的对象将要被销毁);如果你拷贝一个unique_ptr,那么拷贝结束后,这两个unique_ptr都会指向相同的资源,造成在结束时对同一内存指针多次释放而导致程序崩溃。

(3) weak_ptr

weak_ptr:弱引用。 引用计数有一个问题就是互相引用形成环(环形引用),这样两个指针指向的内存都无法释放。需要使用weak_ptr打破环形引用。weak_ptr是一个弱引用,它是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是说,它只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前使用函数lock()检查weak_ptr是否为空指针。它不增加引用计数,只要出了作用域就会自动析构。

传给shared_ptr一个引用,那么引用计数会不会+1

不会。在 C++11 中,可以使用 `std::shared_ptr` 类模板来实现共享所有权的指针。当我们将一个对象或指针传递给 `std::shared_ptr` 构造函数时,该对象或指针的引用计数会自动加一,当所有指向该对象或指针的 `std::shared_ptr` 对象都被销毁时,该对象或指针的引用计数会自动减一。

对于传递给 `std::shared_ptr` 构造函数的应用类型,由于应用本身并没有引用计数,因此不会对其引用计数进行加一操作,也不会影响应用本身的生命周期。相反,`std::shared_ptr` 会通过对应的析构函数来释放对象或指针所占用的内存空间,而不会影响应用本身的生命周期。

需要注意的是,如果我们将一个临时对象或表达式传递给 `std::shared_ptr` 构造函数,它会创建一个临时对象来包装该表达式,并将该临时对象的引用计数加一。因此,在使用 `std::shared_ptr` 时,应该避免将临时对象或表达式传递给构造函数,以避免引用计数的意外增加。

智能指针的循环引用

循环引用是指使用多个智能指针share_ptr时,出现了指针之间相互指向,从而形成环的情况,有点类似

于死锁的情况,这种情况下,智能指针往往不能正常调用对象的析构函数,从而造成内存泄漏。

如何解决

弱指针用于专门解决shared_ptr循环引用的问题,weak_ptr不会修改引用计数,即其存在与否并不影响对象的引用计数器。循环引用就是:两个对象互相使用一个shared_ptr成员变量指向对方。弱引用并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

shared_ptr 的线程安全

虽然我们借shared_ptr 来实现线程安全的对象释放,但是shared_ptr 本身不是100% 线程安全的。它的引用计数本身是安全且无锁的,但对象的读写则不是,因为shared_ptr 有两个数据成员,读写操作不能原子化。根据文档11,shared_ptr 的线程安全级别和内建类型、标准库容器、std::string 一样,即:

一个shared_ptr 对象实体可被多个线程同时读取;

两个shared_ptr 对象实体可以被两个线程同时写入

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

计算机实习秋招全阶段指南 文章被收录于专栏

作者简介:2个月时间逆袭嵌入式开发,拿下理想汽车-ssp、小米汽车-sp、oppo-sp、迈瑞医疗、三星电子等八家制造业大厂offer~ 专栏内容:涵盖算法、八股、项目、简历等前期准备的详细笔记和模板、面试前中后的各种注意事项以及后期谈薪、选offer等技巧。保姆级全阶段教程帮你获得信息差,早日收到理想offer~

全部评论

相关推荐

点赞 13 评论
分享
牛客网
牛客企业服务