Skip to content
Stuart Mentzer edited this page Aug 6, 2015 · 26 revisions

Introduction

This is the preliminary EnergyPlus C++ coding guidelines. It is likely that this will evolve and grow considerably over time.

These guidelines will gradually become enforced by both code scanning tools and code reviewers. Any C++ guideline should allow exceptions for unusual situations: code reviewers should look at the whole picture to see if bending a rule can improve the resulting code in terms of improved clarity, reduced code/duplication, reduced exposure to bugs, and so forth.

At this time EnergyPlus does not adhere to some of these rules due to its recent conversion from Fortran. The intent is to gradually refactor EnergyPlus to use natural C++ constructs and to follow these guidelines.

Source Files

  • Header file names have a .hh extension
  • Source file names have a .cc extension
  • Header and source files (we call these both "source" files in some contexts) have Linux-style (\n) line terminators (dos2unix can convert to this)

Source Organization

Dependencies

  • Code should be organized in conceptual layers with dependencies carefully thought out. Dependencies between source files can become a problem with C++, both in terms of the need to avoid circular dependencies and to avoid long compilation times.
    • High-level components can use and depend on lower level "utility" components but the opposite would indicate a design flaw
    • Finer source granularity can reduce dependency and compile speed problems
  • Ask for help if designing for dependency control is presenting a challenge

Classes

  • One pair of .hh and .cc files per class is usually preferable

Namespaces

  • Namespaces should be used to associate parts of a coherent "package" that work together to provide some functionality
  • Namespaces placed in the corresponding subdirectory can be used to group a package: It is recommended that EnergyPlus start to move to namespace directories and away from a monolithic source directory
  • The use of namespaces increases the benefit of having a .fwd.hh forward declaration header for each class

Source Structure

General

  • No trailing spaces are allowed: Most good editors/IDEs can be set to trim off trailing spaces on Save and stand-alone tools can do this

Indentation

  • Hard tab indentation is used
  • Tip: Setting editors to display tabs as 3+ spaces allows a line to be commented out with // at col 1 without altering indentation alignment

Line Wrapping

  • Line wrapping is discouraged for now: Most editors/IDEs can do soft wrapping in the display
  • Line wrapping that is permitted should wrap at the same indentation as the initial line but with a single extra indent space
    • emacs style wrapping (aligning wrapped lines at the open parenthesis of a function is not allowed
  • Function arguments that are wrapped on separate lines should get an extra tab indent
  • Functions with more than a few arguments should be wrapped to one argument per line
  • Functions with one argument should not wrap the argument to a separate line unless an argument comment is needed or it is part of a family of functions that have wrapped multiple arguments

Header Files

  • Header files have include guards wrapping the whole file of the form
#ifndef NamespaceName_FileName_hh_INCLUDED
#define NamespaceName_FileName_hh_INCLUDED
...
#endif

Includes

  • Includes must be complete and minimal:
    • Headers should include everything they need so that they can be compiled if included alone in a .cc file
    • Headers should not include anything they don't need: "weaker" forward declarations or forward declaration headers should be used instead of full headers wherever they suffice
  • When you modify a file you are responsible for checking for any obsolete, duplicate, or too-strong headers
  • Includes should be grouped into sections in this order and with these comments:
// C++ Headers
...
// Some_Package Headers
...
// ObjexxFCL Headers
...
// EnergyPlus Headers
...
  • A .cc file should include its own header file first in the EnergyPlus Headers section
  • A .hh file should include any base header(s) first in the EnergyPlus Headers section
  • Other headers should be in alphabetical order in each section

Naming

  • CamelCase should be used for type (class, struct, union, enum, ...) names
  • camelCase should be used for variable (including class/struct instance) and function names
  • Exceptions can be made when the case of a name has particular significance such as providing Name() and NAME() methods to get an item's name with Tile or UPPER case
  • C++ library lower_case naming can be used for code that is analogous to a standard library component like a custom container
  • Underscores can be used within more complicated camel case names with multiple parts for readability
  • Use OO naming: names don't need to indicate the concrete class or expose information about the implementation details

Namespaces

  • Namespaces are normally given lowercase names
  • No extra indentation in namespaces
  • Namespaces are marked like this:
namespace thing1 {
namespace thing2 {
...
} // thing2
} // thing1

Formatting Style

Functions

  • Functions with no, one, and multiple arguments should look like this:
return_type
no_arg_function()
{
	...
}

return_type
one_arg_function( arg )
{
	...
}

return_type
multi_arg_function(
	arg1,
	...
	argN
)
{
	...
}
  • Function declarations and implementations must be kept in sync wrt variable names
  • Default arguments should appear only in function declarations when separate declaration and implementation are used

Classes

  • The following format is suggested, with appropriate tailoring, for classes:
class MyClass [: public MyBaseClass]
{

public: // Types        (typedefs, using declarations, etc.)

public: // Creation     (constructors and destructors)

public: // Assignment

public: // Methods

	TypeB const &   (return by value instead of reference if small/builtin type)
	b() const
	{
		return b_;
	}

	TypeB &
	b()
	{
		return b_;
	}

public: // Data        (if any)

	TypeA a;

private: // Data

	TypeB b_;

};
  • Don't decorate member names with m_ prefixes (hurts readability and IDEs can tell you about the variable when you hover your mouse over it)

Blocks (Curly Brackets)

  • Curlies other than on class and function declarations are placed to avoid extra lines of code (to maximize the lines that we can see on the screen)
if ( condition ) {
} else if ( condition ) {
} else {
}
for ( ... ) {
}
while ( ... ) {
}

Whitespace

  • Use one blank line between code sections when it aids clarity
  • Multiple sequential blank lines and extra comment lines filled with repeat characters are strongly discouraged
  • Use spaces to make code more readable for everyone:
    • Put single spaces around operators
    • Put spaces after commas
    • Put spaces inside parentheses of functions
var = 2 * foo( arg1, arg2 );

Comments

  • Leave a single space after // before the comment contents
  • Tag comments directly after the // for some basic categories to aid code searching. The list of tags will evolve but here is a starter set:
  • Permanent comments should be indented (with tabs) to the same column as the code to which they apply
  • Commented out code sections normally should have the `//`` at col 1

Copyright

  • Every source file (.hh and .cc) should have the following copyright comment at the botton of the file (outside of all namespace scoping):
//=================================================================================
//
// NOTICE
//
// Copyright (c) 1996-2015 The Board of Trustees of the University of Illinois
// and The Regents of the University of California through Ernest Orlando Lawrence
// Berkeley National Laboratory. All rights reserved.
//
// Portions of the EnergyPlus software package have been developed and copyrighted
// by other individuals, companies and institutions. These portions have been
// incorporated into the EnergyPlus software package under license. For a complete
// list of contributors, see "Notice" located in main.cc.
//
// NOTICE: The U.S. Government is granted for itself and others acting on its
// behalf a paid-up, nonexclusive, irrevocable, worldwide license in this data to
// reproduce, prepare derivative works, and perform publicly and display publicly.
// Beginning five (5) years after permission to assert copyright is granted,
// subject to two possible five year renewals, the U.S. Government is granted for
// itself and others acting on its behalf a paid-up, non-exclusive, irrevocable
// worldwide license in this data to reproduce, prepare derivative works,
// distribute copies to the public, perform publicly and display publicly, and to
// permit others to do so.
//
// TRADEMARKS: EnergyPlus is a trademark of the US Department of Energy.
//=================================================================================

C++ Usage

Rules

  • Never put a using declaration or directive at file or namespace scope in a header ("infects" including files)
  • Pass large (non-builtin) types by reference
    • This includes std::string!!!
    • In some cases move semantics mean this is relaxed
  • Use ++var and --var, not var++ and var-- if returning the old value is not needed:
    • Faster in the old days with poor optimizers that didn't fix this for you
    • Expresses intent

Recommendations

Classes

  • Don't use this-> prefixes on all class members (hurts readability and is rarely needed for disambiguation)

Const

  • Use const maximally
  • Use const on pass-by-value arguments to have compiler catch someone modifying them in the mistaken assumption that it will alter the passed variable

Aliases

  • Use shorthand reference aliases for complicated objects like array(x).foo(a,b,c).q(3) to reduce typing and thus bug exposures and to improve performance

Assertions

  • Use asserts liberally:
    • Live testing is easier than unit tests for legacy code
    • Serves as enforced documentation
    • Assert function/block pre and post conditions
    • Assert class invariants are preserved after creation and modification

Modernization

  • Prefer natural/native C++ constructs for new and refactored code: Don't just copy and paste similar code: Ask for advice if unsure what a "native" approach might look like
  • Try to avoid global/namespace data in new code where practical
  • Use class owned file resources instead of adding more global files
Clone this wiki locally