Google's C ++ Style Guide. Part 2

Part 1. Introduction

Part 2. Header files

...





When writing code, we all use the rules of code formatting. Sometimes rules are invented, in other cases ready-made style guides are used. Although all C ++ programmers read English more easily than native, it is nicer to have a manual in the latter.

This article is a translation of part of Google's C ++ style guide into Russian.

Original article (fork on github), updated translation .



Header files



It is desirable that each .cc source file has a matching .h header file. There are also known exceptions to this rule, such as unit tests or small .cc files containing only the main () function .



The correct use of header files can have a huge impact on the readability, size, and performance of your code.



The following rules will help you avoid frequent problems with header files.



Independent header files



Header files must be self-sufficient (in terms of compilation) and have the .h extension . Other (non-header) files intended to be included in the code must have the .inc extension and be paired with the include code.



All header files should be self-contained. Users and development tools should not depend on special dependencies when using the header file. The header file must be lockable and include all required files.



It is preferable to place definitions for templates and inline functions in the same file with their declarations. And these definitions must be included in every .ccfile using them, otherwise there may be link errors on some build configurations. If the declarations and definitions are in different files, including one should include the other. Do not separate definitions into separate header files ( -inl.h ). Previously, this practice was very popular, now it is undesirable.



As an exception, if all available variants of template arguments are created from the template, or if the template implements functionality used by only one class, then it is permissible to define the template in one (and only one) .cc file in which this template is used.



There are rare situations when the header file is not self-contained. This can happen when a file is included in a non-standard location, such as in the middle of another file. In this case, there may be no re-enable lock , and additional header files may not be included either. Name such files with the .inc extension . Use them in pairs and try to match the general requirements as much as possible.



Restart lock



All header files must be #define protected against re-inclusion . The macro definition format must be: <PROJECT> _ <PATH> _ <FILE> _H_ .



To ensure uniqueness, use the full file path components in the project tree. For example, the file foo / src / bar / baz.h in the project foo might have the following lock:



#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_


Preliminary announcement



If possible, do not use advance announcements. #Include the required header files instead .



Definition

"Pre-declaration" is a declaration of a class, function, template without a corresponding definition.



Per



  • . #include ( ) .
  • . #include - .




  • , .
  • API, . , API: , , .
  • std:: .
  • , : #include. , #include ( ) :



          // b.h:
          struct B {};
          struct D : B {};
          // good_user.cc:
          #include "b.h"
          void f(B*);
          void f(void*);
          void test(D* x) { f(x); }  // calls f(B*)
          


    #include B D, test() f(void*).
  • , .
  • A code structure that allows for preliminary declaration (and, further, the use of pointers as class members) can make the code confusing and slow.


Verdict



  • Try to avoid pre-declaring entities declared in another project.
  • When using a function declared in a header file, always #include that file.
  • When using a class template, it is preferable to #include its header file.


Also see the rules for inclusion in Names and the Include Order .



Inline functions



Define functions as inline functions only when they are small, for example, no more than 10 lines.



Definition



You can declare functions to be inline and tell the compiler to include them directly in the calling code, in addition to the standard way of calling a function.



Pros



Using inline functions can generate more efficient code, especially when the functions are small. Use this feature for get / set functions, other short and performance critical functions.



Against



Overuse of inline functions can make the program slower. Also, inline functions, depending on their size, can either increase or decrease the size of the code. If these are small functions, then the code can be minified. If the function is large, then the code size can grow very much. Note that on modern processors, leaner code runs faster due to better use of the instruction cache.



Verdict



A good rule of thumb is not to make functions inlineable if they exceed 10 lines of code. Avoid making destructors inlineable, since they can implicitly contain a lot of extra code: calls to variable destructors and base classes!



Another good rule of thumb is that it usually doesn't make sense to inline functions that have loops or switch statements (except in degenerate cases where the loop or other statements are never executed).



It is important to understand that an inline function will not necessarily be compiled into code this way. For example, usually virtual and recursive functions are compiled with a standard call. In general, recursive functions should not be declared inline functions. The main reason for doing inline virtual functions is to place the definition (code) in the class definition itself (for documenting behavior or readability) - often used for get / set functions.



Names and Include Order



Insert the header files in the following order: paired file (for example, foo.h - foo.cc), C system files, C ++ standard library, other libraries, your project files.



All project headers must be relative to the project source directory without using UNIX aliases such as . (current directory) or .. (parent directory). For example, google-awesome-project / src / base / logging.h should be included like so:



#include "base/logging.h"


Another example: if the main function of the dir / foo.cc and dir / foo_test.cc files is to implement and test the code declared in dir2 / foo2.h , then write the header files in the following order:



  1. dir2 / foo2.h .
  2. C (: .h), <unistd.h>, <stdlib.h>.
  3. C++ ( ), <algorithm>, <cstddef>.
  4. .h .
  5. .h .


Separate each (non-empty) group of files with an empty line.



This order of files allows you to detect errors when the required header files (system, etc.) are missing in the paired header file ( dir2 / foo2.h ) and the assembly of the corresponding dir / foo.cc or dir / foo_test.cc files will fail. As a result, the error will immediately appear to the developer working with these files (and not to another team that only uses an external library).



Usually the paired files dir / foo.cc and dir2 / foo2.h are in the same directory (for example, base / basictypes_test.cc and base / basictypes.h ), although this is not required.



Note that C header files such as stddef.h are usually interchangeable with the corresponding C ++ files ( cstddef ). Any variation can be used, but it is best to follow the style of the existing code.



Within each section, the header files are best listed in alphabetical order. Note that previously written code may not follow this rule. If possible (for example, when correcting a file), correct the order of the files to the correct one.



All header files that declare the types you want should be included, except where previously declared . If your code uses types from bar.h , don't rely on another file foo.h to include bar.hand you can limit yourself to including only foo.h : include bar.h explicitly (unless it is explicitly stated (perhaps in the documentation) that foo.h will also give you the types from bar.h ).



For example, the list of header files in google-awesome-project / src / foo / internal / fooserver.cc might look like this:



#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"


Exceptions



There are cases when you need to include header files depending on the conditions of the preprocessor (for example, depending on the OS used). Try to keep such inclusion as short (localized) as possible and place it after other header files. For instance:



#include "foo/public/fooserver.h"
#include "base/port.h"  // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11


Notes:



Image taken from open source .



All Articles