Skip to content

Instantly share code, notes, and snippets.

@z11i
Last active May 16, 2024 10:00
Show Gist options
  • Save z11i/ee550667ec4271fa493d to your computer and use it in GitHub Desktop.
Save z11i/ee550667ec4271fa493d to your computer and use it in GitHub Desktop.
Coding Standards for C++ (Extract)

Coding Standards for C++ (Extract)

  • Naming Conventions
  • Indentation Rules
  • Comments
  • Look & Feel
  • Miscellaneous
  • References
  • Dennis Ritchie, Creator of C

    Naming Conventions

    • Use meaningful names.
    • Use single-character variables only for counters (i, j) or for coordinates (x,y,z).
    Identifier Casing Naming Structure Example
    Class PascalCasing Noun
    class ComplexNumber {...};
    class CodeExample {...};
    class StringList {...};
    Enumeration PascalCasing Noun
    enum Type {...};
    Function, Method camelCasing Verb or Verb-Noun
    void print() {...};
    void processItem() {...};
    Interface PascalCasing ‘I’ prefix Noun
    class IDictionary {...};
    Structure All capital, separate words with ‘_’ Noun
    struct FORM_STREAM_HEADER
    Macro, Constant All capital, separate words with ‘_’
    #define BEGIN_MACRO_TABLE(name) ...
    #define MACRO_TABLE_ENTRY(a, b, c) ...
    #define END_MACRO_TABLE() ...
    const int BLACK = 3;
    Parameter, Variable camelCasing Noun exampleText, dwCount
    Template parameter PascalCasing ‘T’ prefix Noun T, TItem, TPolicy

    A note about test function names: Underscores may be used for test method names if your test method names are long and very descriptive. However, if this style is adopted for test methods, the whole team should follow it consistently. e.g. testLogic_addTask_nullParameters_errorMessageExpected()

    Indentation Rules

    1. Avoid lines longer than 80 characters including preceding spaces and functions longer than than 100 lines of code. [Hint: try this plugin]

    2. Default indentation is one tab. One space is added before and after each operator or assignment symbol.

      Good Bad
       void printMessage() {
           cout << "Welcome\n";
           cout << "Oh yeah\n";
       }
       void printMessage() {
               cout<<"Welcome\n";
           cout<<"Oh yeah\n";
       }
    3. Use blank lines to separate groups of related statements. Omit extra blank lines that do not make the code easier to read.

      Good Bad
       void sortAndPrint(int *data, int size) {
           //sorting
           for (int i = size - 2; i >= 0; i--) {
               for (int j = 0; j <= i; j++) {
                   if (data[j] > data[j + 1]) {
                       int temp = data[j];
                       data[j] = data[j + 1];
                       data[j + 1] = temp;
                   }
               }
           }
       //printing
       for (int i = 0; i < size; i++) {
           cout << data[i] << " ";
       }
       cout << "\n";
      
      }
      void sortAndPrint(int *data, int size) {
      //sorting
      for (int i = size - 2; i >= 0; i--) {
      for (int j = 0; j <= i; j++) {
      if (data[j] > data[j + 1]) {
      int temp = data[j];
      data[j] = data[j + 1];
      data[j + 1] = temp;
      }
      }
      }
      //printing
      for (int i = 0; i < size; i++) {
      cout << data[i] << " ";
      }
      cout << "\n";
      }
    4. Put the opening braces in the same line, not in a new line.

      Good Bad
       void printMessage() {
           if (isCorrect) {
               cout << "Welcome\n";
               cout << "Oh yeah\n";
           } else {
               cout << "Wrong\n";
           }
       }
       void printMessage()
       {
           if (isCorrect)
           {
               cout << "Welcome\n";
               cout << "Oh yeah\n";
           }
           else
           {
               cout << "Wrong\n";
           }
       }
    5. Indent comments at the same level as the code.

      Good:

      // Components must be initialized before they are used.
      initializeComponent();

      Bad:

          // Components must be initialized before they are used.
      initializeComponent();

    Comments

    1. Use // for all code comments (even for multiple line comments; the main reason being that if you ever need to comment out a large chunk of codes for testing, debugging or whatever, you could easily use the pair /* and */ had you been using // for all comments, whereas you couldn’t do that had you used /* and */ for your code comments.

      Good:

      // The following code runs best when the values in
      // array x and those in y are highly correlated.
      // The performance is extremely poor when they are not.

      Bad:

      /*
          The following code runs best when the values in
          array x and those in y are highly correlated.
          The performance is extremely poor when they are not.
      */
    2. Provide relevant comments for important functions.

      Good:

      // This function garbage collects objects created
      // through the factory. Use it with caution, as it
      // may cause performance hiccups.

      Bad: useless comment for not important functions, which are often self-explanatory

      // This function increments the value of x by 1
      void inc() {
          x++;
      }
    3. Write comment for every class definition to describe what it is for, and how it should be used.

      // Iterates over the contents of a GargantuanTable.  Sample usage:
      //    GargantuanTableIterator* iter = table->NewIterator();
      //    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
      //        process(iter->key(), iter->value());
      //    }
      //    delete iter;
      class GargantuanTableIterator {
        ...
      };
    4. Write comment for every function declaration to describe what the function does, and how it should be used. These comments do not describe how the task is been carried out; that should be left to the comments inside the function definition content.

      The following are the types of things to mention in the function declaration:

      • Function parameters and return value
      • For class member functions: whether the object remembers reference arguments beyond the duration of the method call, and whether it will free them or not.
      • If the function allocates memory that the caller must free.
      • Whether any of the arguments can be NULL.
      • If there are any performance implications of how a function is used.

      Good:

      // Returns an iterator for this table.  It is the client's
      // responsibility to delete the iterator when it is done with it,
      // and it must not use the iterator once the GargantuanTable object
      // on which the iterator was created has been deleted.
      //
      // The iterator is initially positioned at the beginning of the table.
      //
      // This method is equivalent to:
      //    Iterator* iter = table->NewIterator();
      //    iter->Seek("");
      //    return iter;
      // If you are going to immediately seek to another place in the
      // returned iterator, it will be faster to use NewIterator()
      // and avoid the extra seek.
      Iterator* getIterator() const;

      Bad:

      // Returns true if the table cannot hold any more entries.
      bool isTableFull();

      Hint: If you are looking for a way to auto-generate online HTML documentation based on the comments written in code, try Doxygen. The comment standard used is similar to Javadoc.

    Look & Feel

    1. Do not declare multiple variables in a single line. Initialize variables whenever possible.

      Good Bad
       int i = 0;
       int j = 0;
       int k = 0;
       int i, j, k;
    2. If there are too many parameters to put in one line, or if you want to comment on the parameters, put one parameter per line, each indented a tab away from the left margin.

      Good:

      bool receive(
          Channel c,                 //comment....
          Request r,                 //comment....
          int &size,                 //comment....
          int &congestion_window,    //comment....
          char *buf);                //comment....

      Bad:

      bool receive(int &size, Channel c, Request r, int &congestion_window, char *buf);
    3. When creating a series of methods that accept the same parameters, do use a consistent order across the functions.

      Good Bad
       void format(Text text, Style style);
       void align(Text text, Style style);
       void format(Text text, Style style);
       void align(Style style, Text text);  // not consistent
    4. The body of the conditional should be wrapped by curly brackets irrespective of how many statements are in it to avoid error prone code.

      Good Bad
       if (isRightCondition(a, b)) {
           printResult();
       }
       if (isRightCondition(a, b))
           printResult();
    5. Do not put more than one statement on a single line.

      Good Bad
       a = 1;
       b = 2;
       if (isRightCondition(a, b)) {
           printResult();
       }
       a = 1; b = 2;
       if (isRightCondition(a, b)) printResult();

    Miscellaneous

    1. Use an enum over static constants or #define values, for the sake of readability.

      Good Bad
       typedef enum{black, white, red, green} Colour;
       ...
       Colour myColour = red;
       ...
       #define black 0;
       const int white = 1;
       #define red 2;
       #define green 3;
       ...
       int myColour = red;
       ...
    2. Do not reference unnecessary libraries, include unnecessary header files, or reference unnecessary assemblies.

    3. Use named constants as const values, instead of #define values. This forces the compiler to do type checking, and also add the variable into symbol table for easy debugging.

      Good Bad
       const int BLACK = 3;
       #define BLACK 3
    4. Use sizeof(var) instead of sizeof(TYPE)

      Good Bad
       MY_STRUCT s;
       ZeroMemory(&s, sizeof(s));
       MY_STRUCT s;
       ZeroMemory(&s, sizeof(MY_STRUCT));
    5. Do not declare public data members. Use inline accessor functions for performance.

      Good Bad
       private:
           int _size;
       public:
           inline int getSize() { return _size; }
       public:
           int _size;
    6. Initialize member variables in the same order that they were defined in the class declaration

      Good Bad
       class SampleCode {
       public:
           SampleCode(int size, string text);
           ~SampleCode();
       private:
           string _text;
           int _size;
       };
      SampleCode ::SampleCode (int size, string text) :
      _text(text),
      _size(size) {
      }
      class SampleCode {
      public:
      SampleCode(int size, string text);
      ~SampleCode();
      private:
      string _text;
      int _size;
      };
      SampleCode ::SampleCode (int size, string text) :
      _size(size),  // The order is wrong
      _text(text) {
      }
    7. Do minimal work in the constructor

    8. Do use a destructor to centralize the resource cleanup of a class that is freed via delete

    9. Do not use virtual methods unless you really should because virtual functions have overhead of calling through the vtable.

    10. Do ensure that all allocated memory is freed using the same mechanisms. Objects allocated using ‘new’ should be freed with ‘delete’.

    11. Do throw exceptions by value and catch exceptions by reference.

      Good Bad
      void processItem(const Item& item) {
          try {
              if (/* some test failed */) {
                  throw Exception(“blah blah blah”);
              }
          }
          catch (Exception &excp) {
              // Process excp
              //
          }
      }
      void processItem(const Item& item) {
          try {
              if (/* some test failed */) {
                  throw Exception();
              }
          }
          catch (Exception excp) {
              // Process excp
              //
          }
      }
    12. Do not allow exceptions to be thrown out of destructors

    13. Do not use catch(Exception e). General exceptions should not be caught. You should catch a more specific exception, or re-throw the general exception as the last statement in the catch block.

    14. Header files are included in the following order in a Header File

      1. System files
      2. Library files
      3. Application-specific files
      4. Local files
      #include <stdio.h>
      #include <string.h>
      #include <appSpecific.h>
      #include "localFiles.h"
    15. Header files are included in the following order in a Source File

      1. System files
      2. Library files
      3. Application-specific files
      4. Local files
      5. Header file for the class

    References:

    Contributions by: Veerabadran Chandrasekaran, Li Mengran, Loke Yan Hao, Vaarnan Drolia, Zhang Zhongwei

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment