Cortex: C++ Style Guide


General Approach and Techniques

  • No (or minimal) explicit memory handling - all memory handles through boost::shared_ptr/boost::shared_array
  • No other 'C' style code now considered unsafe by modern standards, e.g. use std::stringstream over sprintf
  • Use references instead of pointers, except where NULL is a valid value that is explicitly checked for
  • Mark all member functions and function parameter references as const where possible
  • Use std::string instead of char*
  • Use exceptions, but only in exceptional circumstances, otherwise use return codes
  • Use forward references, split code into .h/.cpp files, minimise #includes, use PIMPL and anything else you can do to reduce code coupling
  • The STL and Boost libraries are really, really good. Use them as much as you can and you'll get high quality cross platform functionality for free
  • Always have full warning output turned on (e.g. -Wall flag for GCC), and aim for zero compiler warnings
  • Run your unit tests and other compiled code through valgrind or any other error checking tools you have

Naming

  • The name of a class header file is the same as the class, with the same capitalization. You shouldn't have to go looking to see what the header file for a class is, it is the class name plus a .h extension
  • All cortex classes are to be in the cortex namespace
  • [probably going to change] Naming is to be CamelCase - names of classes are UpperCamelCase (MyExampleClass), names of instances, variables and member functions are lowerCamelCase (myExampleVariable). Underscores can be used in the rare sutuations where the CamelCase becomes unclear, for example when acronyms are involved, e.g. ImageIO_TIF rather than ImageIOTIF
  • Try and show the relation of similar things in their naming by putting the common part of the name first. So instead of calling two classes TiffFileIO and TargaFileIO, consider instead naming them FileIOTiff and FileIOTarga. This will keep both names together in an alphabetical list (e.g. in the Doxygen documentation), as well as the start of their name showing broadly what the class is ahead of the specifics. The same goes for the naming of variables and anything else. It also helps with keeping things vertically aligned, as mentioned earlier:
      // the relation here isn't as clear
      TiffFileIO  tiffReader;
      TargaFileIO targaReader;
    
      // ...as here
      FileIOTiff  fileIOTiff;
      FileIOTarga fileIOTarga;
    

Code Formatting

  • Indent using 2 spaces. Sorry, TABs are great in theory, but they just don't work with a group of developers on different platforms using all manner of different editors and tools, you just wind up with a mix of tabs and all different depths of spaces
  • Always use curly braces, even when not needed. This is going to annoy some people, but there's a bunch of reasons for this:
    • Consistency: if you sometimes use braces and sometimes not it reduces readability
    • Readability: particularly in blocks of code containing nested conditionals and loops, the braces make it a lot easier for humans to read. It also allows some editors to automatically highlight the code blocks (e.g. showing the start/end braces in bold when you're within a conditional)
    • Most importantly, leaving out braces frequently causes silly bugs that are hard to track down: e.g. in the following code, if someone adds a debug statement after the 'if' and neglects to add the braces while they're doing it then the logic changes completely. You're setting a potential trap for people who are going to maintain your code, why would you do that?:
        if (someTest)
          var = true;
      
    • I personally prefer to inline the opening brace, but this one seems to be a 50/50 preference split, and there's no strong argument either way, so use whichever way you prefer, but always try and fit in with the code around you if you're adding to or modifying existing files:
        if (someTest) {
          // fine
        }
      
        if (someTest) 
        {
          // also fine, but I personally think you're wasting the line above here...
        }
      
  • Horizontally align blocks of similar lines (within reason), this aids readability once you get used to it, but more importantly makes cut-n-paste errors more obvious. e.g:
      float  someThing     =  0.3;
      double someThingElse =  4.3;
      float  someThing3    = 10.3;
    
  • Make code self documenting where possible. By slightly changing the layout of your code, names of vairables, etc. you can often make the code sufficiently self evident so that no code comments are required.
    • Break complex conditionals down into more human readable form, e.g. which of these is more likely to be correctly maintained?
        if (((val1 < 0.1) || (val2 < 0.2)) || ignoreBounds) {
          // do something
        }
      
        bool valueTooSmall = (val1 < 0.1) || (val2 < 0.2);
        if (valueTooSmall || ignoreBounds) {
          // do something
        }
      
    • Use whitespace to add meaning to your code, e.g. the following example is just a list of statements, but the whitespace shows that some of them are logically grouped together:
        var = someThing * PI;
        calcNewThing(var);
      
        var2 = somethingElse;
        var3 = somethingElse * 0.5;
        doSomething(var2,var3);
        
        cleanup();
      
  • Use <> for including external header files, and "" for headers within Cortex



Back to the Developers Page