Written in the front: the latest company will start developing a visual product with a large quantity of works, and it needs to provide two times for customers.
SDK, the whole project is written in C++.
This puts forward very high requirements for code quality. At the same time, how to design an elegant and stable API is also a considerable challenge.
Of course, the first problem that a team needs to solve is the establishment of programming specifications. Before, the company’s scale was small, and C++ code specifications were not paid enough attention to, resulting in uneven C++ code quality and different standards.
Therefore, the company leaders want to take the opportunity of visual projects to establish the company’s C++ coding standard, and guide the follow-up c++ development projects. The establishment of coding standard is also a re learning process for C++ language, which helps improve the understanding and use of C++ by the whole team.
After a brief survey, we decided to use Google C++ Coding Style. As the main developer of the project, the experience of studying is recorded as follows: note that this is not the full text translation of Google C++ Coding Style, but the capture.Catch and record some of the key points that may be missing.
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.
（It is recommended to put the declarations and definitions of template classes and implicit functions in a header file. Why? The following article can be explained.
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
(The main name is the naming problem.
1.3 Forward Declaration
Avoid using forward declarations where possible. Just
#include the headers you need.
(Avoid prepositional declarations as much as possible, although pre declaration can reduce compilation time and avoid unnecessary recompiling, but it may avoid the necessary recompiling, can not change the subsequent header file API, but also hide the inheritance relationship between class and class, and so on. In a word, do not usePrepositional statement)
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
(Using inline functions only when the number of lines of code is less than 10 lines, recursive functions do not use inline functions, there are loops in the function, or switch does not use inline functions. Virtual functions can be used, but more is to facilitate or generate documents, although the compiler will not necessarily use it as an inline function.Number processing)
1.5 Names and Orders of Includes
- A blank line
- C system files.
- C++ system files.
- A blank line
- Other libraries’
- Your project’s
(Header files need to be placed under the name of project file, that is, project/dir1/a.h, and do not use relative paths such as. / etc. under UNIX specification.
As to why the header file of the implementation document is put first, the reasons are as follows:
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）
It ensures that the header file contains a complete content, so that if the header file has a problem, then the person that implements the class will first encounter the compiler problem, not the other person who uses the class. Remember, don’t expect to introduce another required header file through a include header.Each header file must be kept self-contained, and the header that you need is directly introduced.
Namespaces are mainly used to avoid name conflicts. There are several points to be noted. One is not to introduce any other name into the STD space. Two is not to introduce all the names in a namespace by using using, but you can introduce a specific name and three if you want to use a namespace.Alias, please use alias in local namespace or local function, that is, local scope, do not use alias in top space, otherwise it will become part of the public API, and finally, do not use inline namespaces.
2.2 Unamed namespaces and Static variables
Unnamed namespaces and static variable declarations can restrict the scope of variables or functions to this file, which can define the same name variables in the outermost scope of different files without a name conflict, and the functions or variables that do not need external links can be placed in the unnamed namespace. InThe explanation of ternal link can be found at https://stackoverflow.com/questions/1358400/what-is-external-linkage-and-internal-.Linkage
2.3 Nonmember, static member and Global functions
The non member function is placed in the namespace, and the global function is used less. Instead of concentrating all static methods into a single class, it’s clear that, even if it’s a static method, you have to put it in a common class that is related to it, and static does not mean that it should be all independent. If it only needs to be seen in this file,Put in the unnamed namespace.
2.4 Local variables
Local variables should be declared near the first place and initialized in time.
2.4 Static and Global variables
This problem is relatively complex, involving many new concepts of c++11& and 14.
First of all, what are trivally destructable: More formally it means that the type has no hasStructor and that all bases and non-static members are trivially destructible. is clear, that is, there is no complex destructor.
All objects with static storage duration are destroyed at program exit (which happens before unjoined threads are terminated. ）
For multithreading, the end of the life cycle of static variables is earlier than the end of unjoined threads. That is to say, a unjoined thread may access a static object that has been destructed, resulting in an error.
Static initialization is divided into dynamic initialization and static initialization, static initialization is the auto zero that we often say, and dynamic initialization involves other operations, such as calling a constructor, and so on, relatively complex. The lifecycle of static objects in different translation unitThere is no order in the starting point. So it may lead to reference to a static object that has not been initialized. The order of destruct is also not guaranteed. Unjoined thread may eventually attempt to access a static object that has been destructed.
So, only when the object is trivally-destructible can it be used as a global or static state, because trivally-desctructible is not affected by the order of the destructor. Constexpr because it is a compilation period, soIt is a simple structrue.
From the initialization point of view, as long as it is not constant initialization (constant initialization）Then its initialization order cannot be guaranteed, so Dynamic initialization of nonlocal variables is discouraged, and in general it isOrbidden. does not guarantee that the initialization of the variable is independent of the initialization order of other variables (or the initialization of other static variables will not be referenced to this variable).
The dynamic initialization of local static variables is OK and is not affected by the above rules.
Rales said so much, that is, the initial and structural order of the static variable is uncertain, so for this kind of variable, it is initialized only by the constant and relieves the dependence on the order. The structure is also guaranteed to be trival.
2.5 thread-local variables
The lifetime of a local thread variable is similar to a static variable, but each thread has a separate copy, and the variable is generated by the thread creation and the end of the thread.
Similar to static variables, local thread variables are also faced with initialization order problems (unless declared in function bodies), but they do not face the problem of sequencing.
If you want to declare in the outer layer, please initialize constants for variables.
(Unfinished to be continued… )