乐趣区

关于c++:C大厂面试真题

C++ 规范库的 map 和 set 有什么区别,如何实现的?

  • map 和 set 都是 C ++ 的关联容器,其底层实现都是红黑树。
  • map 和 set 区别在于:

    • map 中的元素是 key-value(键 - 值)对:关键字起到索引的作用,值则示意与索引相关联的数据;set 是关键字的简略汇合,set 中的元素都只蕴含一个关键字。
    • set 的迭代器是 const 的,不容许批改元素的值;map 容许批改 value,但不容许批改 key。

    其起因是 map 和 set 是依据关键字排序来保障其有序性的,如果容许批改关键字的话,那么首先须要删除该键,而后调节树均衡,再插入批改后的键值,再从新调节树均衡。这样会毁坏 map 和 set 的构造,导致迭代器生效。

    • map 反对下标操作,set 不反对下标操作。

map 底层为什么要用红黑树实现?

  • 红黑树的特点:红黑树是二叉查找树,但在每个节点减少一个存储为示意节点的色彩,能够是红色或彩色,通过对任意一条从根到叶子的门路上各个节点着色形式的限度,红黑树确保没有一条门路会比其余门路长两倍。因而,它是一种弱均衡二叉树,绝对于严格的均衡二叉(AVL)树来说,它的旋转次数少,所以对于查找、插入、删除较多的状况下,通常应用红黑树。
  • AVL 是严格均衡的,频繁的插入和删除,会引起频繁的再均衡,导致效率升高;红黑树是弱均衡的,算是一种折中,插入最多旋转 2 次,删除最多旋转 3 次。所以红黑树在查找、插入、删除的复杂度都是 O(logn),且性能稳固,所以 STL 外面很多构造包含 map 底层都是应用的红黑树。

简述 weak_ptr 的作用

  • weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,因为没有重载 operator* 和 ->,所以它不能像一般指针那样应用。
  • weak_ptr 最大作用在于帮助 shared_ptr 工作,像旁观者那样观测资源的应用状况。weak_ptr 能够从一个 shared_ptr 或者另一个 weak_ptr 对象结构,取得资源的观测权。但 weak_ptr 没有共享资源,它的结构不会引起 shared_ptr 援用计数的减少。
  • 应用 weak_ptr 的成员函数 use_count() 能够观测资源的援用计数,另一个成员函数 expired() 的性能等价于 use_count()==0,示意被观测的资源曾经不存在。weak_ptr 也能够应用成员函数 lock() 从被观测的 shared_ptr 取得一个可用的 shared_ptr 对象,从而操作资源。但当 expired()==true 的时候,lock() 函数将返回一个存储空指针的 shared_ptr。
  • 简略来说就是:

    • 观测 shared_ptr 资源应用状况。
    • 解除 shared_ptr 循环援用问题.

C/C++ 的参数入栈程序为什么是从右向左?

  • 从右向左压栈的程序是与 C /C++ 反对可变参数无关的。C/C++ 要求在申明参数可变的函数时,须要有至多一个确定的参数。为什么呢?因为须要有一个参数为函数提供可变参数的类型(否则函数怎么晓得如何解析后续的可变参数?比方,可变参数列表中有两个参数,一个 int 型,一个 byte 型,函数在解析可变参数表时,怎么晓得这 5 字节的数据到底应该如何去解析)如果一个可变参数的参数类型当时确定的话,这个参数就没有存在的意义了。
  • 如果参数入栈程序是从左向右压栈,第一个参数(即形容可变参数表各变量类型的那个参数)将被放在栈底,因为可变参的函数第一步就须要解析可变参数表的各参数类型,即第一步就须要失去上述参数,因而,将它放在栈底是很不不便的。当然,从左向右压栈的话也能够实现可变参的性能,然而这样的话,该性能实现起来会简单些。

个别程序的虚拟内存空间为什么是 4g?

  • 因为寻址空间取决于 cpu 地址线条数,如 32 位机,寻址空间为 2^32 = 4G,所以最大只反对 4G 的寻址空间,即便插了 8G 的内存条也只能应用 4G 内存。

Duilib 为什么绘图性能不好?

  • (答案仅供参考)Duilib 是 DirectUI 思维的一种实现。DirectUI 艰深来说就是在窗口上指定一块区域(仅仅是一个区域,不是一个实体控件)通过各种音讯模仿一个控件的性能。齐全能够在一个对话框类的 OnMouseMove、OnLButtonDown 等函数中模仿一个按钮进去。然而模仿的控件一多就凌乱了,为了对立治理,逻辑上更清晰相似于实体控件。把每种控件封装成类解决各种音讯,并通过自定义的音讯散发机制把音讯散发到各个模仿控件里。这种模仿的形式绘制和音讯解决效率相比于实体控件要低。
  • Duilib 的图片绘制代码中也有影响性能的中央,所有的控件的图片绘制都是调用 CControlUI 的 DrawImage 函数,而此函数调用了 CRenderEngine 的 DrawImageString 函数。在绘制图片时,DrawImageString 会解析图片字符串的属性,而后找到对片的 HBITMAP 资源,最初调用真正的绘图函数去绘制。问题就在于每绘制一个图片都会再次解析一次字符串,当界面比较复杂,而且图片字符串也比较复杂时,这个解析的过程就影响了程序效率。当然这能够通过缓存图片资源解析后果的形式来优化。

什么是内存泄露?如何查看内存泄露?

  • 内存透露是指在程序中动静申请的内存或者资源在应用完后,没有开释。这样可能导致程序应用的内存一直增大,最终会因零碎内存不足,而导致程序解体或其余谬误。
  • 在 Windows 下能够通过工作管理器查看内存应用状况,能够简略剖析是否有内存透露。也有很多像 VLD 这样的内存透露检测工具。如果是应用 VC 库来写程序的话,在 Debug 版本中也能够应用 VC 的 C 运行库中提供的像_CrtCheckMemory、_CrtCheckMemory、_CrtMemCheckpoint、_CrtMemDifference、_CrtMemDumpAllObjectsSince 等函数来检测和定位内存透露问题。

C++ 程序解体的个别起因是什么?怎么定位解体问题?

  • 程序解体个别有 3 个起因:

    • 操作了野指针
    • 内存拜访谬误(包含格式化数据类型谬误、索引越界等)
    • 堆栈溢出
  • 在 Windows 下咱们个别会在编译程序时保留其 pdb 文件,设置解体时生成 dump 文件。因而,能够通过 VS 或者 Windbg 联合 pdb 文件来剖析解体产生的 dump。大部分时候,通过 Windbg 的“!analyze -v”命令咱们就能定位到解体问题的代码行。如果解体的代码行不是理论引起问题的中央,咱们也能够通过相干代码的上下文联合 log 以及解体前操作等景象来剖析解体起因。最初,还能够通过 dump 查看解体时其余的堆栈或者线程信息,做进一步剖析。
退出移动版