Style Guide

Google programming style has been widely adopted in software development.

Summary (for C++)

Header Files

  • Be self-contained

  • Avoid forward declaration

  • The format of the symbol name in #define guard: <PROJECT>_<PATH>_<FILE>_H_

  • Names and order of includes

    • Related header (the header that the current .cc file plans to implement or test)

    • C system headers

    • C++ standard library headers

    • Other libraries' .h files

    • Your project's .h files

    • Conditional includes

#include "foo/server/fooserver.h"  // e.g., the current file is fooserver.cc

#include <sys/types.h>
#include <unistd.h>

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"

#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11

Scoping

  • With few exceptions, place code in a namespace.

  • Namespaces should have unique names based on the project name, and possibly its path.

  • Do not use using-directives (e.g., using namespace foo). -- This pollutes the namespace!

  • Do not use inline namespaces.

  • Do not use namespace aliases at namespace scope in header files.

Class

  • Use a struct only for passive objects that carry data; everything else is a class.

  • Use a struct instead of a pair or a tuple whenever the elements can have meaningful names.

  • All inheritance should be public.

  • Overload operators judiciously. Do not use user-defined literals.

  • Define operators only on your own types.

  • Make classes' data members private, unless they are constants.

Functions

  • Non-optional input parameters should usually be values or const references.

  • Use overloaded functions (including constructors) only if a reader can easily get it.

  • Default arguments are allowed on non-virtual functions when the default is guaranteed to always have the same value.

  • Use trailing return types only where using the ordinary syntax (leading return types) is impractical or much less readable.

Google-Specific Magic

  • Prefer to have single, fixed owners for dynamically allocated objects.

  • Prefer to transfer ownership with smart pointers.

  • Use cpplint.py to detect style errors.

Other C++ Features

  • We do not use C++ exceptions.

  • Avoid using run-time type information (RTTI). (by use of typeid or dynamic_cast.)

  • Use C++-style casts like static_cast<float>(double_value). Do not use cast formats like (int)x unless the cast is to void. You may use cast formats like T(x) only when T is a class type.

  • Use the prefix form (++i) of the increment and decrement operators unless you need postfix semantics. (There can be a performance difference in certain cases.)

  • We strongly recommend using const in APIs wherever it is meaningful and accurate.

  • You should not use the unsigned integer types such as uint32_t, unless there is a valid reason such as representing a bit pattern rather than a number. When in doubt, use a larger type.

  • Avoid defining macros, especially in headers; prefer inline functions, enums, and const variables.

  • Use nullptr for pointers, and '\0' for chars (and not the 0 literal).

  • Prefer sizeof(varname) to sizeof(type).

  • Use type deduction only if it makes the code clearer to readers who aren't familiar with the project.

  • Use lambda expressions where appropriate. Prefer explicit captures when the lambda will escape the current scope.

Naming

  • Use names that describe the purpose or intent of the object. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader.

  • Filenames should be all lowercase and can include underscores (_) or dashes (-).

  • Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

  • The names of variables (including function parameters) and data members are all lowercase, with underscores between words. Data members of classes (but not structs) additionally have trailing underscores. For instance: a_local_variable, a_struct_data_member, a_class_data_member_.

  • Variables declared constexpr or const, and whose value is fixed for the duration of the program, are named with a leading "k" followed by mixed case. Underscores can be used as separators in the rare cases where capitalization cannot be used for separation.

  • Regular functions have mixed case; accessors and mutators may be named like variables.

  • Namespace names are all lower-case, with words separated by underscores.

  • Enumerators (for both scoped and unscoped enums) should be named like constants, not like macros. That is, use kEnumName not ENUM_NAME.

  • Exceptions: If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme.

// Type Names
class UrlTable { ...             // classes
struct UrlTableProperties { ...  // structs
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap; // typedefs
using PropertiesMap = hash_map<UrlTableProperties *, std::string>; // using aliases
enum class UrlTableError { ...   // enums

// Variable Names
std::string table_name;  // common variable names
class TableInfo {        
 private:
  std::string table_name_;  // class data member - underscore at end
  static Pool<TableInfo>* pool_;
};
struct UrlTableProperties {
  std::string name;         // struct data member - no underscore
  static Pool<UrlTableProperties>* pool;
};

// Const Names
const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24;  // Android 8.0.0

// Function Names
AddTableEntry()
DeleteUrl()
OpenFileOrDie()

// Enumerator Names
enum class UrlTableError {
  kOk = 0,
  kOutOfMemory,
  kMalformedInput,
};

// Exceptions
bigopen() // function name, follows form of open()
uint      // typedef
bigpos    // struct or class, follows form of pos
sparse_hash_map  // STL-like entity; follows STL naming conventions
LONGLONG_MAX     // a constant, as in INT_MAX

Comments

  • Use either the // or /* */ syntax, as long as you are consistent.

  • Start each file with license boilerplate.

  • Every non-obvious class or struct declaration should have an accompanying comment that describes what it is for and how it should be used.

  • Declaration comments describe use of the function (when it is non-obvious); comments at the definition of a function describe operation.

  • In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

  • Note: I personally follows the Doxygen style for comments. Also, @ is preferred over \ for Doxygen commands.

/**
 * @brief Abstract base class for Foo.
 */
class Foo {
 public:
  /**
   * @brief Constructor
   *
   * @param node configuration, which must contain one param: mem_var of double type
   */
  Foo(const Yaml::Node& node); 
  
 private:
  const double mem_var_;  ///< inline comments, 2 spaces before slash
};

Formatting

  • Each line of text in your code should be at most 80 characters long. (controversial)

  • Non-ASCII characters should be rare, and must use UTF-8 formatting.

  • Use only spaces, and indent 2 spaces at a time.

  • See others by examples below.

// Function Declarations and Definitions
ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
  DoSomething();
}
ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
                                             Type par_name3) {
  DoSomething();
}
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    Type par_name1,  // 4 space indent
    Type par_name2,
    Type par_name3) {
  DoSomething();  // 2 space indent
}

// Function Calls
bool result = DoSomething(argument1, argument2);
bool result = DoSomething(argument1, argument2,
                          argument3);  // wrap at parentheses
bool result = DoSomething(
    argument1, argument2, argument3);  // new line with 4 space indent

// Floating-point Literals
float f = 1.0f;  // bad: float f = 1.f;
float f2 = 1;    // Also OK  
long double ld = -0.5L;  // bad: long double ld = -.5L;
double d = 1248.0e6;     // bad: double d = 1248e6;

// Conditionals
if (condition) {     // no spaces inside parentheses, space before brace
  DoOneThing();      // two space indent
  DoAnotherThing();
} else if (int a = f(); a != 3) { // closing brace on new line, else on same line
  DoAThirdThing(a);
} else {
  DoNothing();
}
if (x == kFoo) return new Foo();  // allow one exception
if (x == kQuz) { return new Quz(1, 2, 3); } // a space between closing parenthesis

// Loops and Switch Statements
switch (var) {
  case 0: {  // 2 space indent
    ...      // 4 space indent
    break;
  }
  default: {
    assert(false);
  }
}

// Pointer and Reference Expressions
// These are fine, space preceding.
char *c;
const std::string &str;
int *GetPointer();
std::vector<char *>
// These are fine, space following (or elided).
char* c;
const std::string& str;
int* GetPointer();
std::vector<char*>  // Note no space between '*' and '>'

// Boolean Expressions
if (this_one_thing > this_other_thing &&
    a_third_thing == a_fourth_thing &&
    yet_another && last_one) {
  ...  // be consistent: && is always at the end of the lines
}

// Return Values
return result;  // No parentheses in the simple case.
// Parentheses OK to make a complex expression more readable.
return (some_long_condition &&
        another_condition);
// Do not needlessly surround the return expression with parentheses.
// Use parentheses in return expr; only where you would use them in x = expr;.

// Preprocessor Directives
  if (lopsided_score) {
#if DISASTER_PENDING      // Correct -- Starts at beginning of line
    DropEverything();
#endif
    BackToNormal();
  }

// Class Format
// Sections in public, protected and private order, each indented one space.
class MyClass : public OtherClass {
 public:      // Note the 1 space indent!  
  MyClass();  // Regular 2 space indent.
  explicit MyClass(int var);
};

// Constructor Initializer Lists
MyClass::MyClass(int var) : some_var_(var) {
  DoSomething();   // When everything fits on one line
}
MyClass::MyClass(int var)  
    : some_var_(var), some_other_var_(var + 1) {
  DoSomething();   // wrap before the colon and indent 4 spaces
}
MyClass::MyClass(int var)
    : some_var_(var),             // 4 space indent
      some_other_var_(var + 1) {  // lined up
  DoSomething();
}
MyClass::MyClass(int var)
    : some_var_(var) {}

// Namespace Formatting
namespace {

void foo() {  // Correct.  No extra indentation within namespace.
  ...
}

}  // namespace

Last updated