Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Info

This document was drawn from C++ Layout and Comments on the Trac/Wiki. There have been some significant re-formatting for Confluence. The content on this page should be verified before the Trac/Wiki pages are removed.

Numbered Headings
skip-headingsh4
start-numbering-with6
start-numbering-ath2

Layout and Comments

Layout

6-1. Multiple statements per line SHOULD NOT be used.

Code Block
languagecpp
// NO!
value = 10; setHex(value); doLess();

This is too hard to read and debug. Always use separate lines.

6-2. Basic indentation MUST be 4 spaces.

Code Block
languagecpp
for (i = 0; i < nElements; i++) (
    a[i] = 0;
}

Indentation of 1 is too small to emphasize the logical layout of the code. Indentation larger than 4 makes deeply nested code difficult to read and increases thechance that the lines must be split. Choosing between indentation of 2, 3, and 4; 2 and 4 are the more common. We require 4 because it is more visually obvious.

6-3. Deeply nested code SHOULD be avoided.

Code that is too deeply nested is hard to both read and debug. One should replace excessive nesting with function calls.

6-4. Block layout SHOULD be as illustrated in example 1 below (K&R, strongly recommended) not as in example 2 or 3.

Code Block
languagecpp
// Example 1:
while (!done) {        // Yes
    doSomething();
    done = moreToDo();
}
// Example 2:
while (!done)
{                      // No
    doSomething();
    done = moreToDo();
}
// Example 3:
while (!done)
    {                    // NO
      doSomething();
      done = moreToDo();
    }

Example 3 introduces an extra indentation level which doesn't emphasize the logical structure of the code as clearly as example 1. Example 2 adds an additional line without significant increase in readability.

6-5. The class declarations SHOULD have the following form:

Code Block
languagecpp
class SomeClass :
    public  BaseClass1,
    public  BaseClass2,
    private BaseClass3
{
public:
    SomeClass() {}
protected:
    ...
private:
    ...
};

Note that:

  • Like functions, the opening brace is at the same indentation as the class keyword
  • any subclasses are indented one block and their visibility is explicitly qualified
  • The declarations publicprotected and private are left-justified to the same indentation as class.
  • If SomeClass is not derived from anything, the opening brace should still line up with class

For historical reasons, the format:

Code Block
languagecpp
class SomeClass : public BaseClass1, BaseClass2, private BaseClass3 {
public:
    SomeClass() {}
protected:
    ...
private:
    ...
};

is permitted but not encouraged, and should not be used in new code.

6-6. Function declarations MAY have any of the following three forms:

Code Block
languagecpp
/**
 * Documentation
 */
void someMethod(type arg,               ///< Helpful comment about arg
                type2 arg2              ///< Helpful comment about arg2
               )
{
    ...
}

Note that:

  • The first argument immediately follows the opening paren of the argument list, and other arguments are aligned with it
  • The closing paren of the argument list is on a line by itself, and lines up with the opening paren
  • If there are no arguments, the function may be written as void someOtherMethod(), but the opening brace still gets a line of its own
  • The opening brace is aligned with the return type

 

Code Block
languagecpp
/**
 * Documentation
 */
void someMethod(
    type arg,                       ///< Helpful comment about arg
    type2 arg2                      ///< Helpful comment about arg2
) {
    ...
}

Documentation for function arguments may be placed after the arguments, as shown here, or in the main documentation block using @param.

 

Code Block
languagecpp
void someMethod(type arg) {
    ...
}

The third form is permitted only for functions with a small number of arguments.

6-7. The 'if-else' class of statements SHOULD have the following form:

Code Block
languagecpp
if (condition) {
    statements;
}

if (condition) {
    ...
} else {
    ...
}

if (condition) {
    statements;
} else if (condition) {

    statements;
} else {
    statements;
}

This is equivalent to the Sun recommendation. 

6-8. A 'for' statement SHOULD have the following form:

Code Block
languagecpp
for (initialization; condition; update) {
    statements;
}

This follows from the general block rule above.

6-9. Empty loops SHOULD be avoided. But if needed, empty loops MUST be clearly identified and on a single line:

Code Block
languagecpp
for (initialization; condition; update) {}// do nothing here

This emphasizes that the statement is empty and it makes it obvious for the reader that this is intentional.

6-10. A 'while' statement SHOULD have the following form:

Code Block
languagecpp
while (condition) {
    statements;
}

This follows from the general block rule above.

6-11. A 'do-while' statement SHOULD have the following form:

Code Block
languagecpp
do {                    // better yet: use a 'while (condition) {}'
    statements;
} while (condition);

This follows from the general block rule above.

6-12. A 'switch' statement SHOULD have the following form:

Code Block
languagecpp
switch (condition) {
  case ABC:
    statements;
    // Fallthrough

  case DEF:
    statements;
    break;

  case XYZ:
    statements;
    break;

  default:
    statements;
    break;
}

Note that each 'case' keyword is indented 2 spaces relative to the 'switch' statement as a whole and the statement blocks are indented one indention (4 spaces). This makes the entire 'switch' statement stand out.

The explicit 'Fallthrough' comment should be included whenever there is a 'case' statement without a 'break' statement. Leaving the 'break' out is a common error, and it must be made clear that it is intentional when it is not there.

6-13. A 'try-catch' statement SHOULD have the following form:

Code Block
languagecpp
try {
    statements;
} catch ( std::logic_error const & logicError ) {
    statements; // stifling the exception
} catch ( ... ) {
    statements; throw;
}

This follows partly from the general block rule above. The discussion about closing brackets for 'if-else' statements apply to the 'try-catch' statements. If the 'catch' clause is not going to re-throw the exception, a comment indicating so for clarity is a good idea.

6-14. Single statement 'if-else' , 'for' or 'while' statements MUST only be written without brackets if on one line.

Code Block
languagecpp
if (condition) statement;

while (condition) statement;

for (initialization; condition; update) statement;

It is a common recommendation (Sun Java recommendation included) that brackets should always be used in all these cases. Brackets are in general a language construct that groups several statements and thus by definition superfluous on a single statement. However, the use of brackets in the above cases would make it trivial to add statements without error.

6-15. The function return type SHOULD be put on the same line as the function name.

Code Block
languagecpp
void MyClass::myMethod (void){
    ...
}

This is general practice.

6-15a. The minimum number of parentheses needed for syntactic correctness and readability SHOULD be used.

Code Block
languagecpp
Yes:  a = b(nSigmaToGrow*sigma + 0.5)
No:   a = b((nSigmaToGrow*sigma) + 0.5)

 

White Space

6-16. The following white space conventions SHOULD be followed: ¶

  • Conventional operators should be surrounded by a space character (except * and / and %)
  • C++ reserved words should be followed by a white space.
  • Commas should be followed by a white space.
  • Colons should be surrounded by white space.
  • Semicolons in for statements should be followed by a space character.

    Code Block
    languagecpp
    a = (b + c)*d;              // NOT:   a=(b+c)*d
    a = y%4 == 0                // NOT:   a = y % 4 == 0
    while (true) {              // NOT:   while(true) ...
    doSomething(a, b, c, d);    // NOT:   doSomething(a,b,c,d);
    for (i = 0; i < 10; i++) {  // NOT:   for (i=0;i<10;i++){

Makes the individual components of the statements stand out. Enhances readability. It is difficult to give a complete list of the suggested use of whitespace in C++ code. The examples above however should give a general idea of the intentions.

6-18. Logical units within a block SHOULD be separated by one blank line.

Enhance readability by introducing white space between logical units of a block.

6-19. Methods SHOULD be separated by one blank line in .h files and two blank lines in .cc files.

By making the space larger than space within a method, the methods will stand out within the file. However, this must be balanced with being able to see more of the code at a glance (one screen), which enhances readability through increased context.

6-20. Variables in declarations SHOULD be left aligned where possible.

Code Block
languagecpp
AsciiFile  *file;
int        nPoints;
float      x, y;

Enhance readability. The variables are easier to spot from the types by alignment.

6-21a. Alignment SHOULD be used wherever it enhances readability.

Code Block
languagecpp
if      (a == lowValue)    computeSomething();
else if (a == mediumValue) computeSomethingElse();
else if (a == highValue)   computeSomethingElseYet();

value = (potential        * oilDensity)   / constant1 +
        (depth            * waterDensity) / constant2 +
        (zCoordinateValue * gasDensity)   / constant3;

minPosition     = computeDistance(min,     x, y, z);
averagePosition = computeDistance(average, x, y, z);

switch (value) {
    case PHASE_OIL   : strcpy(string, "Oil");   break;
    case PHASE_WATER : strcpy(string, "Water"); break;
    case PHASE_GAS   : strcpy(string, "Gas");   break;
}

There are a number of places in the code where white space can be included to enhance readability even if this violates common guidelines. Many of these cases have to do with code alignment. General guidelines on code alignment are difficult to give, but the examples above should give a general clue. 

6-21b. Nested namespaces SHOULD be aligned left with each level of nesting on a new line.

The closing braces should all appear on one line and should be commented with the full nested namespace.

Code Block
languagecpp
namespace lsst {
namespace level1 {
namespace level2 {

   class MyClass {
      // ...
   };

}}} // lsst::level1::level2

This is a common practice in the C++ community, until the proposed level1::level2::level3 syntax is supported.

Comments

DocumentationStandards contains most of the rules about comments. A few detailed rules are listed here.

6-22. Tricky code SHOULD not be commented but rewritten!

Sometimes tricky code is unavoidable, but if the choice is between being clever and being clear, choose clarity.

6-23. All comments MUST be written in English.

Comments should not be about the obvious logic of the code, rather they should provide expanded information about why an action is being done, or some non-obvious result or side effect.

In an international environment English is the preferred language.

6-24. Block comments MUST never be mixed with lines of code.

This:

Code Block
languagecpp
/* Get an antenna reference
 * and if it is pointed at the Sun,
 * point it at the moon, after checking
 * to see if the moon is blue.
 */

Antenna & = getAntenna("bima.ant1");
bool moonIsBlue = (Planet.MOON.getColor() == "blue");
if(ant.isPointedAt(Planet.SUN) && moonIsBlue) {
    ant.pointAt(Planet.MOON);
} else {
    ant.pointAt(Planet.VENUS);
}

Not this:

Code Block
languagecpp
/* Get antenna reference */ Antenna &ant = getAntenna("bima.ant1");
/* and if it is pointed  */ bool moonIsBlue = (Planet.MOON.getColor() == "blue");
/* at the Sun, point it */  if(ant.isPointedAt(Planet.SUN) && moonIsBlue) {
/* at the moon */                ant.pointAt(Planet.MOON);
/* after checking */        } else {
/* if the moon is blue */        ant.pointAt(Planet.VENUS);
}

Commenting in the second way makes code difficult to read and difficult to modify.

6-25. Comments SHOULD be included relative to their position in the code.

Code Block
languagecpp
// YES:
while (true) {
    // Do something
    something();
}

// NOT:
while (true) {
// Do something now
    something();
}

This maintains consistency by positioning the comment at the same level as the code being discussed.