前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多年C++开发使用经验总结

多年C++开发使用经验总结

作者头像
IT大咖说
发布2018-12-29 10:59:22
2.6K0
发布2018-12-29 10:59:22
举报
文章被收录于专栏:IT大咖说IT大咖说

内容来源:作者——shengofbig,链接:https://www.jianshu.com/p/d01472734a78,好文请多支持!谢谢你的阅读。

阅读字数:4277 | 11分钟阅读

摘要

借着公司内和其他小组的一个分享,把自己几年来C++开发的一点思考总结一下。全篇没有高屋建瓴的观点,基本都是些细节方面的注意事项。希望能给大家提供一点帮助。

构建工具

C/C++世界里有不少的构建工具:make、autotools、scons、CMake、Bazel。但近几年比较流行的,也就是CMake和Bazel。所以这一部分,也就大概对比下这两个工具吧。

究竟该选择哪个工具,我觉得可以从如下几个方面来对比一下:

1、上手难度

因为Bazel采用了类似Python的语法,所以其学习曲线相比CMake要平缓一些。但当我们考虑上手难度时,除了学习曲线之外,还要考虑文档的完备性、该工具的通用性等各个角度。当综合考虑时,我觉得CMake是一个尽管保守但仍旧不错的选择。主要原因就在于,CMake几乎已经成为现在C++的事实标准。使用CMake,就意味着:

  • 你可以把你熟悉CMake的技能用在折腾别的C++项目上。而这点之所以重要,是因为你在利用某个第三方库的时候,往往需要大概研究下它的编译过程。
  • CMake的官方文档和stackoverflow上的问答也比较完善。一旦遇到一个问题,往往通过搜索引擎能快速的得到答案。

另外,从设计理念上来看,CMake提供的解决方案是改革式的:它并没有提供一个全新的解决方案,而是和Make、Visual Studio或者其他现有的构建工具来结合使用的。而这就使得你无需丢弃在其他工具上所积累起来的开发经验——例如你熟悉make工具,哪怕是一个CMake维护的项目,你也可以毫不费力就知道如何来查看编译参数,以及控制编译并发度等等。

而对于Bazel则不是如此。Bazel完全以革命者的姿态完整提供了一整套解决方案,所有的使用细节你都要从头开始。加上文档的匮乏,这就使得你也得花上一段时间,才能熟悉Bazel。

2、thirdparty的管理

Bazel内置了对thirdparty源码级别依赖的支持https://docs.bazel.build/versions/master/external.html

  • thirdparty可以是用Bazel构建的,也可以不是。对于非Bazel项目,你需要额外为其添加一个Bazel的描述文件。
  • thirdparty可以是一个本地项目,也可以是一个git仓库或者http链接

所以总的来看,Bazel对thirdparty支持还是非常友好的。

就这点对比来看,CMake其实做的是不太好的。CMake尽管也有ExternalProject https://cmake.org/cmake/help/latest/module/ExternalProject.html的feature,但根据实际经验来看,使用和维护都比较的复杂。所以我还是更倾向于写几个脚本来下载和编译这些thirdparty依赖。

这里可以拿我参与维护的Pegasus https://github.com/XiaoMi/rdsn/tree/master/thirdparty项目为例。在该项目中,我们依赖了几个不同类型的项目:

  • 从构建工具上来看,这些依赖有使用CMake的,有使用make的,有使用autotools的
  • 从来源上来看,有的依赖来自git仓库,有的来自http链接,有的则是从一个大的项目里面挑选了一个更小的模块使用
  • 从代码的使用方式上来看,有的是直接拿来用,有的还需要稍微修改下源代码。

而通过shell脚本,这些各种各样的场景我们都能非常方便、直接、易维护的得以支持。

3、其它

Bazel和CMake当然还有些其它方面值得对比,但并非一些通用的点,这里就简单列举下,不再详细展开了:

  • IDE集成
  • 缓存编译结果,从而加速编译过程
  • 多语言混合变成的支持
  • 分布式编译
  • 跨平台的支持

再补充一个别人的讨论链接https://github.com/PaddlePaddle/Paddle/issues/681, 有需求的可以参考一下。

编程规范

强烈推荐Google C++ Style:https://google.github.io/styleguide/cppguide.html。尽管它禁止了很多C++ feature而被很多人黑的很惨,但从工程的角度而言,它的确提供了非常多极其中肯的建议。说到底,编程规范的存在,主要就是可以让水平参差不齐的工程师们,可以在一起协作出风格较为一致的项目来。

也存在一些工具可以对google规范进行检查:

  • clang-format https://clang.llvm.org/docs/ClangFormat.html
  • cpplint https://github.com/cpplint/cpplint

因为google的规范文档对C++ feature的取舍原因讲的非常好,这里就不再赘述了。唯一想补充的是异常:

C++在语法层面对异常支持不太友好:你无法通过函数签名来得知一个函数到底会抛出哪些异常。例如:

代码语言:javascript
复制
void GetSomeResource(const char* resource_name);

如果这个接口没有良好文档或注释,并且也没有代码可翻时,你在调用这个接口时很有可能会漏掉一些错误情况——因为它可能抛出异常。更要命的是,一个疏于捕获的异常一旦触发,线上的程序就会crash。

其实解释这么多,大家只要和Java中的异常机制对比一下,就高下立判了。对于这个话题,王垠的这篇博客http://www.yinwang.org/blog-cn/2017/05/23/kotlin值得一看的。

  • 在运维Pegasus项目时,遇到过一个老版本glibc的bug:如果多个线程同时抛出异常,程序会陷入死循环。这个bug的发现也是个有趣的过程,后面我专门写篇文章展开吧。
  • 在禁用异常后,程序就只能用错误码来进行错误处理。对于很多项目,大家都采用一套类似的范式,可以参考tensorflow的做法https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/lib/core/status.h

C++的新特性

如果能使用C++的新特性,当然是尽量使用的好。我自己在开发中,觉得非常方便必须使用的新特性有:

  • 智能指针
  • 右值,以及C++14中右值得capture
  • lambda, bind
  • initialize list

想补充说一下的是auto,我自己不是特别喜欢这个feature,也非常赞同google规范中的对auto的限制:仅当可以提高代码可读性时,使用auto

这里不由得就想扯起java 10中的var。虽然能方便开发,但觉得更多的是会被滥用。而一个可能被滥用的feature,还不如没有的好。

第三方utility

在做项目开发的时候,一般会有很多琐碎的需求,从而也需要很多utility工具包。这里把我遇到的一些需求整理一下:

  • 算法和数据结构:stl, boost
  • 错误码管理:参见tensorflow https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/lib/core/status.h
  • C语言的字符串封装:string_view https://github.com/abseil/abseil-cpp/blob/master/absl/strings/string_view.h
  • 字符串的各种操作、转换、打印:可以多翻翻abseil https://github.com/abseil/abseil-cpp, 以及folly https://github.com/facebook/folly,另外也推荐fmtlib https://github.com/fmtlib/fmt
  • 线程安全的、无锁的数据结构、线程池: folly
  • google全家桶:gtest,gflags, glog, protobuf, grpc

最后,也推荐下kudu这个项目,里面有自己实现的一些工具包https://github.com/cloudera/kudu/tree/master/src/kudu/util,以及对google开源项目中utility的整理https://github.com/cloudera/kudu/tree/master/src/kudu/gutil

单元测试

每个程序员都讨厌写测试。就我自己而言,我觉的单元测试的目的有以下几个:

  • 确保功能的实现和预期一致
  • 防止程序在重构的时候出问题
  • 给模块的使用者,提供使用示例

值得一提的是,对于C++项目,除了功能性测试之外,你最好还能让你的单元测试通过一些自动化工具的检测,如:

  • valgrind:检查内存泄露,以及非法访存
  • Address Sanitizer:检测非法访存https://github.com/google/sanitizers/wiki/AddressSanitizer
  • Thread Sanitizer:检测线程竞争https://clang.llvm.org/docs/ThreadSanitizer.html

写在最后

自己的整理这些内容时,脑子里反复萦绕的一个问题是:我们在开发一个项目时,所要遵守的各种流程和规范到底是不是真的有必要的?说的更直白一点就是,“代码洁癖”这东西到底有没有意义?

我的看法是:代码洁癖不是一个原则,而是在投入和产出上的一种权衡。如果仅仅快速试错,那么就不需要维持代码洁癖,因为你完全不知道你今天写的代码究竟能存活多久。而如果是一个马拉松式的项目,代码洁癖就值得维持,因为它对于项目的维护的确很有意义。

最后,贴一个自己比较喜欢的C++博客https://preshing.com/

以上为今天的分享内容,谢谢大家!

IT大咖说 | 关于版权

由“IT大咖说(ID:itdakashuo)”原创的文章,转载时请注明作者、出处及微信公众号。投稿、约稿、转载请加微信:ITDKS10(备注:投稿),茉莉小姐姐会及时与您联系!

感谢您对IT大咖说的热心支持!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT大咖说 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档