写在前面:最新公司马上就要开始开发一款视觉产品,工程量较大,且需要对客户提供可以二次开

发的SDK,整个项目用C++编写。

这就对代码质量提出了非常高的要求,同时,如何设计出优雅稳定的API也是相当大的挑战。

当然,团队首先需要解决的问题是编程规范的确立。之前,公司规模较小,对C++代码规范不够重视,导致各个C++项目代码质量参差不齐,标准不一。

所以,公司领导希望借此视觉项目的机会,建立起公司C++编码规范,统一指导后续c++开发项目。建立编码规范本身也是对C++语言的再学习过程,利于提高整个团队对C++的理解和使用。

经过简单调研,我们决定使用Google C++ Coding Style。作为项目主要开发人员,现将学习的心得记录如下,注意,这里不是对Google C++ Coding Style的全文翻译,而是捕捉和记录一些可能遗漏的要点。

1、Headers

1.1 self-contained headers

Header files should be self-contained (compile on their own)

Prefer placing the definitions for template and inline functions in the same file as their declarations. The definitions of these constructs must be included into every .cc file that uses them, or the program may fail to link in some build configurations.

As an exception, a template that is explicitly instantiated for all relevant sets of template arguments, or that is a private implementation detail of a class, is allowed to be defined in the one and only .cc file that instantiates the template.

(推荐将模板类和内敛函数的声明和定义放在一个头文件里面,为什么?下面的文章可以说明。

When the compiler encounters a declaration of a TestTemp object of some specific type, e.g., int, it must have access to the template implementation source. Otherwise, it will have no idea how to construct the TestTemp member functions. And, if you have put the implementation in a source (TestTemp.cpp) file and made it a separate part of the project, the compiler will not be able to find it when it is trying to compile the client source file. And, #includeing the header file (TestTemp.h) will not be sufficient at that time. That only tells the compiler how to allocate for the object data and how to build the calls to the member functions, not how to build the member functions. And again, the compiler won't complain. It will assume that these functions are provided elsewhere, and leave it to the linker to find them. So, when it's time to link, you will get "unresolved references" to any of the class member functions that are not defined "inline" in the class definition.)

1.2 The #define guard

<PROJECT>_<PATH>_<FILE>_H_

(主要是命名格式问题)

1.3 Forward Declaration

Avoid using forward declarations where possible. Just #include the headers you need.

(尽量避免使用前置声明,虽然前置声明可以减少编译时间,避免不需要的重编译,但是还是可能会规避掉必要的重新编译,无法在后续对头文件API进行更改,还会隐藏类与类之间的继承关系导致多态失效等等,总之,不要用前置声明)

1.4 Inline Functions

Define functions inline only when they are small, say, 10 lines or fewer.

Another useful rule of thumb: it's typically not cost effective to inline functions with loops or switch statements

(只在代码行数少于10行的情况下使用内联函数,递归函数不要使用内联函数,函数内有循环或者switch不要使用内联函数,虚函数可以使用内敛,但是更多是为了方便或者生成文档,虽然编译器不一定会将它作为内联函数处理)

1.5 Names and Orders of Includes

  1. dir2/foo2.h.
  2. A blank line
  3. C system files.
  4. C++ system files.
  5. A blank line
  6. Other libraries' .h files.
  7. Your project's .h files.

(头文件需要放在project文件名下,即project/dir1/a.h,不要使用UNIX规范下的./..等相对路径。

至于为什么要把该实现文件的头文件放在第一个,原因如下:

Including the .h file as the very first line of the .c file ensures that no critical piece of information intrinsic to the physical interface of the component is missing from the .h file (or, if there is, that you will find out about it as soon as you try to compile the .c file)

它能确保头文件包含的内容完整,这样,如果头文件有问题,那么实现这个类的人将首先碰到编译问题,而不是留给其他使用这个类的人。记住,不要指望通过include某个头文件来顺带引入另个需要的头文件,之前说过,每个头文件都要保持self-contained,直接引入你需要的那个header就好。)

2. Scoping

2.1 NameSpace

名称空间主要是用来避免名称冲突。有几点需要注意的,一是不要往std空间引入其他任何的名称,二是不要通过使用using来引入一个名称空间下所有的名称,但你可以引入某个具体的名称,三是如果要对名称空间使用别名,请在局部名称空间或局部函数,即局部作用域使用别名,不要在顶级空间使用别名,否则将会成为对外公开API的一部分,最后就是不要使用内联名称空间。

2.2 Unamed namespaces and Static variables

未命名的名称空间和静态变量声明可以限制变量或者函数的作用域为本文件,这样就可以在不同的文件中的最外层作用域定义同名变量而不会出现名称冲突,不需要外部链接的函数或者变量都可以放到未命名名称空间里面。internal link的解释可以参见https://stackoverflow.com/questions/1358400/what-is-external-linkage-and-internal-linkage

2.3 Nonmember, static member and Global functions

非成员函数放到名称空间里面,少用全局函数。不要将所有的静态方法集中组合到一个单独的类中,说白了,哪怕是静态方法,你也得放在一个与之相关的普通的类中,静态不代表就应该全部独立出来。如果只需要本文件可见,放入未命名名称空间里。

2.4 Local variables

局部变量尽量在靠近第一次使用的地方声明,并及时初始化。

2.4 Static and Global variables

这个问题相对比较复杂,涉及到很多c++11&14的新特性新概念。

首先关于什么是trivally destructable: More formally it means that the type has no user-defined or virtual destructor and that all bases and non-static members are trivially destructible. 说白了,就是没有复杂的析构函数

All objects with static storage duration are destroyed at program exit (which happens before unjoined threads are terminated. )

关于多线程的情形,静态变量的生存周期结束的时刻是要早于unjoined线程被结束的时刻的。也就是说,unjoined线程可能访问到一个已经被析构的静态对象从而导致出错。

静态对象的初始化分为动态初始化和静态初始化,静态初始化即我们常说的自动置零,而动态初始化则涉及其他的操作,例如调用一个构造函数等,相对复杂。不同translation unit中的静态对象的生存周期的起始点没有一定先后顺序。所以就可能导致引用一个尚未初始化的静态对象。析构的顺序同样不能保证,unjoined线程最终可能试图访问一个已经被析构的静态对象。

所以,只有对象是trivally-destructible的时候,才能被用作全局或静态,因为trivally-desctructible不受析构的顺序的影响。constexpr因为是编译期确定,所以也算作简单可析构。

从初始化角度来看,只要不是常量初始化(constant initialization)那么其初始化顺序就无法保证,因此 Dynamic initialization of nonlocal variables is discouraged, and in general it is forbidden. 除非保证该变量的初始化与其他变量的初始化顺序无关(或者说其他静态变量的初始化不会引用到这个变量)

局部静态变量的动态初始化是OK的,不受上述规则影响。

啰里啰嗦说了那么多,总结起来就是,静态变量初始和析构顺序不确定,所以,对于这类变量,只用常量初始化,解除对顺序的依赖。析构也保证要trival。

2.5 thread-local variables

局部线程变量的生存期类似于静态变量,但是每个线程都有一个独立的拷贝,变量生成于线程创建,卒于线程结束。

类似于静态变量,局部线程变量也会面临初始化顺序问题(除非在函数体内声明),但不会面临析构顺序问题。

如果要在外层声明,请对变量进行常量初始化。

(未完待续……)

Google C++ Coding Style 学习笔记的更多相关文章

  1. Google Guava14.0 瓜娃学习笔记

    Guava 是java api的增强与扩展,提供复杂的java 数据结构,使你的代码更简短精炼,具有良好的可读性.看看guava给我们提供了哪些很酷的功能: 集合创建: Map<String, ...

  2. python coding style guide 的高速落地实践

    python coding style guide 的高速落地实践 机器和人各有所长,如coding style检查这样的可自己主动化的工作理应交给机器去完毕,故发此文帮助你在几分钟内实现coding ...

  3. python coding style guide 的快速落地实践——业内python 编码风格就pep8和谷歌可以认作标准

    python coding style guide 的快速落地实践 机器和人各有所长,如coding style检查这种可自动化的工作理应交给机器去完成,故发此文帮助你在几分钟内实现coding st ...

  4. Google's C++ coding style

    v0.2 - Last updated November 8, 2013 源自 Google's C++ coding style rev. 3.274 目录 由 DocToc生成     头文件   ...

  5. 学习笔记之Coding / Design / Tool

    CODING 学习笔记之代码大全2 - 浩然119 - 博客园 https://www.cnblogs.com/pegasus923/p/5301123.html 学习笔记之编程珠玑 Programm ...

  6. Google TensorFlow深度学习笔记

    Google Deep Learning Notes Google 深度学习笔记 由于谷歌机器学习教程更新太慢,所以一边学习Deep Learning教程,经常总结是个好习惯,笔记目录奉上. Gith ...

  7. c coding style之学习篇

    1. 使用do-while结构去避免潜在的内存泄漏问题. do {     p1 = malloc(10);     if (null == p1)     {         break;     ...

  8. vue学习笔记(三)class和style绑定

    前言 通过上一章的学习vue学习笔记(二)vue的生命周期和钩子函数,我们已经更近一步的知道了关于vue的一些知识,本篇博客将进一步探讨vue其它方面的内容,vue中关于class和style绑定,关 ...

  9. Google coding Style Guide : Google 编码风格/代码风格 手册/指南

    1 1 1 https://github.com/google/styleguide Google 编码风格/代码风格 手册/指南 Style guides for Google-originated ...

随机推荐

  1. Linux下Apache2.2和PHP5的安装配置

    Linux下Apache2.2和PHP5的安装配置 环境介绍 我安装使用的Linux版本为CentOS6.5最精简版,Apache为2.2.29,PHP版本为5.4.28. 系统安装 首先安装Cent ...

  2. hust 1590 - 方块游戏 数学

    1590 - 方块游戏 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/problem/show/1590 D ...

  3. JS 判断PC、android、ios、微信浏览器

    1.通过js userAgent来判断 <h1>判断访问此链接的操作系统</h1> <script> var Agents = new Array("An ...

  4. AR(Average Recall, 平均查全率), ANMRR(Average Normalized Modified Retrieval Rate, 平均归一化检索秩)

    AR(Average Recall, 平均查全率), ANMRR(Average Normalized Modified Retrieval Rate, 平均归一化检索秩)

  5. Scrapy入门教程(转)

    关键字:scrapy 入门教程 爬虫 Spider作者:http://www.cnblogs.com/txw1958/出处:http://www.cnblogs.com/txw1958/archive ...

  6. IOS上传图片方法类

    IOS上传图片方法类   iPhone开发中遇到上传图片问题,找到多资料,最终封装了一个类,请大家指点,代码如下 // // RequestPostUploadHelper.h // demodes ...

  7. @ResponseBody,@RequestBody,@PathVariable

    最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...

  8. ionic开发环境搭建之ios

    前言 公司在做完ionic androud版后就开始做ios版,虽然ios的坑我觉得比起androud少了很多,但是作为第一次接触ios的我来说,环境实在太麻烦,从搭环境到打包一个正式版的ios ap ...

  9. WebView 加载网页和java 与js交互

    [mw_shl_code=java,true]WebView是一个可以显示网页的控件.需求:通过WebView加载assets下的html文件.实现页面的缩放.向menu键添加:前进.后退和刷新,实现 ...

  10. VisualStudio:WEB 性能测试和负载测试 入门

    背景 一直做的是中小企业应用,很少关注性能和负载这里,进来准备看一本关于并发编程的图书,为了量化的测试 WEB 环境的性能和负载,特意玩了一下 VS 提供的测试项目. 新的测试项目 新建项目 性能测试 ...