面向 Java 程序员的 C++ 入门指南 ----- 1
背景介绍
本文旨在为 Java 程序员提供一个最快的入手 C++ 进行常规项目开发的指南。本文假设阅读者具有相当程度对 Java 语言的理解和开发经验,但是出于各种原因需要进行常规的 C++ 项目开发。本文旨在介绍工作中常规 C++ 项目中经常被用到或被误用的内容,从而帮助 Java 程序员快速上手 C++,而非一个面面俱到的 C++ 教程。
本文以 C++11 标准为基础,部分内容涉及到 C++14/17 中引入的新的标准库(STL,Standard Template Library)内容,但是通常这部分内容可以通过第三方库在 C++11 中使用(例如 Abseil)。这么选择是因为高版本的编译器还没有得到很好的普及和应用,大家在这种情况下最有可能用到的基本上也就是 C++11/14/17 了。
相较于常规的 C++ 教程:
- 本文压缩了关于语法语义方面的知识,因为 C++ 的语法语义和 Java 非常相似,熟练的 Java 程序员应该能无障碍阅读 C++ 代码
- 本文增加了语言内建提供的标准库的对比,用于帮助 Java 程序员快速找到自己经常使用的工具
- 本文特别强调了一些 C++ 开发中经常用错或者不容易用对的地方,以及在这些地方应该遵循一个什么样的原则进行处理
- 本文还介绍了一些常用 C++ 周边生态,包括但不限于:
- 构建系统
- 包管理
- 常见第三方类库
- 常见编码 Idiom
- 静态代码分析
- 动态错误分析
- 代码调试
- Profiling
快速开始
配置 IDE/编辑器
可以按照使用 VSCode 进行远程开发进行配置。
创建 Blade 项目
以下都在远程开发机上操作,Blade 相关文档见Blade 从入门到精通,Blade使用手册(最新更新2020-09-28)和Blade功能手册(2020-09-15)。
- 创建所有 Blade 工程的根目录(非必须)mkdir ~/BladeWorkspaces
- 创建我们这个工程的目录(我们称这个目录为 BLADE_ROOT 目录) mkdir ~/BladeWorkspaces/HelloWorldWorkspace && cd ~/BladeWorkspaces/HelloWorldWorkspace
- 进行 blade 初始化 blade init
- 创建我们自己的相对目录,假设我们的 repo 最终会放到 https://code.byted.org/zhangshuai.ds/helloworld/,则该目录应该位于 mkdir -p zhangshuai.ds/helloworld && cd zhangshuai.ds/helloworld
- 创建 main.cc 和 BUILD 文件
- 使用 blade 编译 cd $BLADE_ROOT && blade build -p debug zhangshuai.ds/helloworld
- 想要运行程序的话可以使用 blade run -p debug zhangshuai.ds/helloworld 来运行,单测把 run 改成 test
- 打包发布程序的话,在 build 的同时加上参数 --bundle=<debug|release> 打包,release 需要在 BUILD 文件中指定一个绝对路径,打包后的文件需要部署到这个绝对路径下
// zhangshuai.ds/helloworld/main.cc
#include <cstdio>
int main(void) {
printf("Hello World!\n");
return 0;
}
# zhangshuai.ds/helloworld/BUILD
cc_binary(
name = "hello_world",
srcs = ["main.cc"],
)
其他构建系统
C/C++ 世界中比较常见的构建系统还有:
- Autotools + Makefile:https://opensource.com/article/19/7/introduction-gnu-autotools
- CMake: https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1#file-effective_modern_cmake-md
- Bazel:个人觉得比 blade 要合理一点
常见的包管理器有: - 依赖发行版的包管理器提供(例如 apt/rpm/...)
- 自己管理(例如 复制代码到 third_party 文件夹下/git submodule/自己写脚本拉代码编译/...)
- vcpkg/conan
- 构建系统自己集成但需要用户做些事情(cmake/bazel/...)
C++ 的依赖管理是需要严肃对待的,比 Java 更容易出问题。Java 依赖管理中比较常见的一类问题就是编译的时候依赖了高版本的库,运行的时候部署了低版本的库,结果用到的某个方法不存在,直接就抛异常了。C++ 由于继承自上古时期的头文件/代码分离的机制,使得整个事情更容易出问题。而且实现质量比较低的第三方库,更容易出现各种复杂的资源管理问题,以及 Undefined Behavior 问题。另一类常见的问题是菱形依赖问题,Java 中这样的问题如果跑起来没事甚至可以不怎么管,但是 C++ ABI(Application Binary Interface)不兼容的情况太多了,基本上都会出问题。
所以如果你的组里没有一个非常资深的同学搞定这一套东西,而且你在写公司的项目的话,最好还是用 blade 别瞎折腾了。如果在公司外写非常严肃的大型项目,建议使用 bazel(但是用起来很麻烦,真的要人工去搞定每一个依赖和所有间接依赖)。