C++ Coding Standards: 101 Rules, Guidelines, and Best Practices Notes

Table of Contents

The C++ In-Depth Series

Accelerated C++: Practical Programming by Example, Andrew Koenig and Barbara E. Moo

Applied C++: Practical Techniques for Building Better Software, Philip Romanik and Amy Muntz

The Boost Graph Library: User Guide and Reference Manual, Jeremy G. Siek, Lie-Quan Lee, and Andrew Lumsdaine

C++ Coding Standards: 101 Rules, Guidelines, and Best Practices, Herb Sutter and Andrei Alexandrescu

C++ In-Depth Box Set, Bjarne Stroustrup, Andrei Alexandrescu, Andrew Koenig, Barbara E. Moo, Stanley B. Lippman, and Herb Sutter

C++ Network Programming, Volume 1: Mastering Complexity with ACE and Patterns, Douglas C. Schmidt and Stephen D. Huston

C++ Network Programming, Volume 2: Systematic Reuse with ACE and Frameworks, Douglas C. Schmidt and Stephen D. Huston

C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, David Abrahams and Aleksey Gurtovoy

Essential C++, Stanley B. Lippman

Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions, Herb Sutter

Exceptional C++ Style: 40 New Engineering Puzzles, Programming Problems, and Solutions, Herb Sutter

Modern C++ Design: Generic Programming and Design Patterns Applied, Andrei Alexandrescu

More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions, Herb Sutter

For more information, check out the series web site at www.awprofessional.com/series/indepth/

Acknowledgments

Inspiration for some of the "sound bites" came from many sources, including the playful style of [Cline99], the classic import this of [Peters99], and the legendary and eminently quotable Alan Perlis.

[Cline99] M. Cline, G. Lomow, and M. Girou . C++ FAQs (2ndEdition) (Addison-Wesley, 1999).

[Peters99] T. Peters . "The Zen of Python" (comp.lang.python, June 1999).

0. Don't sweat the small stuff. (Or: Know what not to standardize.)

Here are several common issues where the important thing is not to set a rule but just to be consistent with the style already in use within the file you're maintaining:

Don't specify how much to indent, but do indent to show structure: Use any number of spaces you like to indent, but be consistent within at least each file.

Don't enforce a specific line length, but do keep line lengths readable: Use any length of line you like, but don't be excessive. Studies show that up to ten-word text widths are optimal for eye tracking.

Don't overlegislate naming, but do use a consistent naming convention: There are only two must-dos: a) never use "underhanded names," ones that begin with an underscore or that contain a double underscore; and b) always use ONLYUPPERCASENAMES for macros and never think about writing a macro that is a common word or abbreviation (including common template parameters, such as T and U; writing #define T anything is extremely disruptive). Otherwise, do use consistent and meaningful names and follow a file's or module's convention. (If you can't decide on your own naming convention, try this one: Name classes, functions, and enums LikeThis; name variables likeThis; name private member variables likeThis_; and name macros LIKETHIS.)

Don't prescribe commenting styles (except where tools extract certain styles into documentation), but do write useful comments: Write code instead of comments where possible (e.g., see Item 16). Don't write comments that repeat the code; they get out of sync. Do write illuminating comments that explain approach and rationale.

1. Compile cleanly at high warning levels

Examples

Example 1: A third-party header file. A library header file that you cannot change could contain a construct that causes (probably benign) warnings. Then wrap the file with your own version that #includes the original header and selectively turns off the noisy warnings for that scope only, and then #include your wrapper throughout the rest of your project. Example (note that the warning control syntax will vary from compiler to compiler):

/ File: myproj/mylambda.h – wraps Boost's lambda.hpp / Always include this file; don't use lambda.hpp directly. / NOTE: Our build now automatically checks "grep lambda.hpp <srcfile>". / Boost.Lambda produces noisy compiler warnings that we know are innocuous. / When they fix it we'll remove the pragmas below, but this header will still exist. / #pragma warning(push) // disable for this header only #pragma warning(disable:4512) #pragma warning(disable:4180) #include <boost/lambda/lambda.hpp> #pragma warning(pop) // restore original warning level

Example 2: "Unused function parameter." Check to make sure you really didn't mean to use the function parameter (e.g., it might be a placeholder for future expansion, or a required part of a standardized signature that your code has no use for). If it's not needed, simply delete the name of a function parameter:

// … inside a user-defined allocator that has no use for the hint …

// warning: "unused parameter 'localityHint'" pointer allocate( sizetype numObjects, const void *localityHint = 0 ) { return staticcast<pointer>( mallocShared( numObjects * sizeof(T) ) ); }

/ new version: eliminates warning pointer allocate( sizetype numObjects, const void * /* localityHint * = 0 ) { return staticcast<pointer>( mallocShared( numObjects * sizeof(T) )); }

Example 3: "Variable defined but never used." Check to make sure you really didn't mean to reference the variable. (An RAII stack-based object often causes this warning spuriously; see Item 13.) If it's not needed, often you can silence the compiler by inserting an evaluation of the variable itself as an expression (this evaluation won't impact run-time speed):

// warning: "variable 'lock' is defined but never used" void Fun() { Lock lock;

// …

}

// new version: probably eliminates warning void Fun() { Lock lock; lock;

// …

}

Example 4: "Variable may be used without being initialized." Initialize the variable (see Item 19).

Example 5: "Missing return." Sometimes the compiler asks for a return statement even though your control flow can never reach the end of the function (e.g., infinite loop, tHRow statements, other returns). This can be a good thing, because sometimes you only think that control can't run off the end. For example, switch statements that do not have a default are not resilient to change and should have a default case that does assert( false ) (see also Items 68 and 90):

// warning: missing "return" int Fun( Color c ) { switch( c ) { case Red: return 2; case Green: return 0; case Blue: case Black: return 1; } }

// new version: eliminates warning int Fun( Color c ) { switch( c ) { case Red: return 2; case Green: return 0; case Blue: case Black: return 1; default: assert( !"should never get here!" ); // !"string" evaluates to false return -1; } }

Example 6: "Signed/unsigned mismatch." It is usually not necessary to compare or assign integers with different signedness. Change the types of the variables being compared so that the types agree. In the worst case, insert an explicit cast. (The compiler inserts that cast for you anyway, and warns you about doing it, so you're better off putting it out in the open.)

2. Use an automated build system

3. Use a version control system

4. Invest in code reviews

5. Give one entity one cohesive responsibility

Author: Shi Shougang

Created: 2015-03-05 Thu 23:21

Emacs 24.3.1 (Org mode 8.2.10)

Validate