为什么说 C++ 的序列容器 array 是 C 数组的一个更好的替代品? |直播分享实录

69920983bac66001eb25975e16973d48.gif

3 月 27 日晚 8 点(昨晚),著名 C++ 专家吴咏炜,Boolan 首席咨询师在线开讲《C++ 序列容器》,精彩实战的干货分享,引来不少开发者基于实际开发场景的真实提问与答疑。

为此,笔者将昨晚公开课的部分视频内容整理成文,分享给更多的技术爱好者。

8e9f73d128d9267561b6af4a0aeaed26.png

*扫描小助手二维码获取回放视

06292728072c824f9af2250b23c4a2be.png

C 数组的更“好”替代品 array

C++ 的序列容器 array 是 C 数组的一个更好的替代品。首先,它在性能方面跟 C 数组一样,栈上分配。这跟我们后面讲的 vector 不同。它也跟 C 数组一样,你需要在编译期确定这个数组的大小。

为什么要使用 array?因为它解决了 C 数组中的两个怪异问题。这两个问题密切相关,我们后面会详细讲解。其一是在直接传参时,会出现退化行为,导致被调用的函数无法获取 C 数组的长度。

6450d970252d69aeb3dc77310969d7a0.png

不过,在 C++ 里如果用引用传参的话,仍能获得 C 数组的长度。

如果我们按照传统的 C 的方式传参的话,它就会退化,就得不到这个长度。另外,C 数组是不能按值拷贝的。而 array 的行为跟我们讲的其他容器差不多,它提供了 begin、end、front、back、size 这样一些通用的成员函数,行为上更加一致。此外,它直接支持等号、小于这样的比较运算,使用起来也会比较方便。

5b569f146021895c3fa992e30f7505a7.png

如何应对参数退化?

我们先看一下退化这个问题。 

退化的问题,一种典型的错误情况是使用 ARRAY_LEN 这样获得数组长度的宏。在 C 的环境里,我们可能会这样写,拿数组的 sizeof取得它的大小,除以数组里第一项的大小,这样我们就能获得这个数组的长度。

如果我们一不小心写出了屏幕上这样的代码,那就麻烦大了。这样情况下,它的行为跟你的预想不一致,大家如果没看出来结果是啥,首先说一下这个结果不是 8。很多老手一定知道这个地方会出现什么结果了,但可能还是有很多人不知道问题在哪里。

36a8c69cdb28a1c13adef5218c97054d.png

这个问题,到了 C++ 17 有改进的方式,我们可以使用 size 函数来解决。如果我们把 size 用在这个地方,先定义一个数组,用 size 取它的长度,这样是可以的。如果我们调这个 test,那根本不能通过编译,直接编译失败,而不是返回给一个错误的结果。因为 size 函数只接受一个数组,不接受一个数指针。 

1baa86579ef217895bab95047a9a1245.png

a73d3e8c19617245575e0dd7a93c22ef.png

数组对象复制问题

另一个相关的一个问题是数组对象的复制。C 数组既不能用来初始化另一个 C 数组,也不能互相赋值。这两部分代码都是不能编译的。

array 的话就没这个问题。类似行为的代码完全是可以编译的,这个行为比较符合直观了。这两个问题,C 的数组不能复制和 C 的数组的传参退化,是相关联的,我们可以说是因为数组不能复制,所以 C 的数组传参会退化,也可以说是因为,C 设计的时候,希望数组能够方便地按指针的方式传参,设计了数组传参的退化行为。然后,为了一致起见,也不支持拷贝动作了——因为我们传参,可以认为是一个拷贝初始化的动作。所以既然传参不行,拷贝初始化当然也就不行了。这两个是相关联的问题。

93316fffe2155850d0fb16475cd3444f.png

另外一个问题是 C 的数组的可读性存在问题,尤其是跟另外一些函数声明等复杂语法结合到一起的时候。

40705be30830ddc0d9fb15c4bc0ab942.png

我们来看一下,你能一眼看得出定义的到底是什么吗?到底是数组还是指针?这个很绕吧?是的。

如果真需要用到这么复杂的东西,绝对不建议用 C 的数组的方式来写,用 array 的话,就比较直观。

95df77d71a9a69984dc030e1c5daa586.png

精彩Q&A

在直播答疑环节,有不少开发者在线提问,吴老师进行了解答,受篇幅限制,本文节选几个问题与大家分享。

Q1:list 为什么不能排序?

吴咏炜:list 不是不能排序,list 是不能使用标准算法来排序。标准算法要求参数是随机访问迭代器,支持随机访问。list 的迭代器不是随机访问迭代器。但双向链表本身是有可以应用的排序算法,因此可以使用成员函数来进行排序。

Q2:推荐的 STL 源码?

吴咏炜:要阅读现在的现代 C++ 的标准库的源码,用 Clang 的 libc++ 可读性会比较高。

Q3:用 boost 靠谱吗?

吴咏炜:boost 挺靠谱的, boost 里面代码是评审过的,它的质量有一定的保证。当然 boost 太大,没有必要去学会使用 boost 里面的所有库。一般来讲,很多编码规范里也会说,不建议引入整个 boost,它会说允许使用 boost 里面的某些库,按照需求来引入。

Q4:除了 Jupyter Notebook,有什么其他方式能看到对象的操作过程吗?

吴咏炜:像这种交互式的,我只知道 Cling 系列。除了浏览器里的 xeus-cling,还有命令行交互式的 cling。我觉得 xeus-cling 比较好,使用 Jupyter Notebook 非常方便。当然你也可以用调试器,一步步单步调试,在调试器里检查对象内容,这也不是不可以。还有就是我刚才介绍的那个 output_range,实际上就是多用打印输出的方式了。

更多精彩内容,大家可以扫描小助手二维码,领取 C++ 的序列容器公开课更多精彩回放,或者查看往期吴老师公开课回放视频,本次公开课的内容,在 4 月 13 日举办的《现代 C++ 实战培训》中,老师会进一步结合案例进行讲解。

670589caf4f80f823348d7221c5e56c8.png

扫码领取公开课回放视频

现代C++实战课程大纲

d8f1d8a479c844f252790be4965bd99c.png

现代C++实战培训

自 C++ 11 以来,C++ 以每三年一版的频度发布着新的语言标准,C++ 11/14/17/20 每一版都在基本保留向后兼容性的同时提供着改进和新功能。本课程围绕这些现代 C++ 的改进、功能和相关编程实践,讲解现代 C++ 现代C++ 11/14/17/20 语言的特性,帮助学员深入掌握现代 C++新特性的意义(Why)、具体功能(What),及如何在实践中应用这些新特性(How)。

94a2384cf921dcd4488d9b74abb33570.png

授课形式

全程直播,总课时 20 课时(每课时 50 分钟)

开班日期

2024 年 4 月 13 日开始,每周六、日 20:00—21:40(共 10 次课,节假日顺

延)

培训导师

c2310b9f2162ae442e6525ea53d4a4b5.png

吴咏炜,现任 Boolan 首席咨询师,国内著名C++专家,曾任英特尔亚太研发中心资深系统架构师,近 30 年 C/C++系统级软件开发和架构经验。专注于 C/C++ 语言(包括C++98/11/14/17/20)、软件架构、性能优化、设计模式和代码重用。对于精炼、易于维护的代码和架构有着不懈的追求,对开源平台(GNU/Linux)有深入的理解。长期担任资深技术教练,涉及 C++、软件架构、安全软件开发、开源软件等多方面。

9ada0cd01ed02677a02ba3832427a854.png

吴咏炜老师的《现代C++实战培训》课程是 Boolan技术赋能培训的品牌课程,在华为、博世西门子、银科、大疆等很多著名企业进行内训,都获得企业的高度认可和参训学员一致好评,为参会企业和听众搭建一个高端、开放、技术交流平台,欢迎大家踊跃报名参加,今日购课享受最后一天早鸟价优惠,欢迎大家联系小助手了解详情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值