CppCodingConventions

From LucidDB Wiki
Jump to: navigation, search

Please see CodingConventions and GenericCodingConventions for language-independent rules.


Contents

Header Files

All header files should follow the pattern below:

      /*
      // $Id: Snafu.h#1 $
      // ... Project boilerplate ...
      */
      #ifndef Fennel_Snafu_Included
      #define Fennel_Snafu_Included

      #include "fennel/device/Fiasco.h"

      FENNEL_BEGIN_NAMESPACE

      /**
       * A Snafu is a rather mundane kind of Fiasco.
       *
       * @author Polly Nomial
       * @version $Id: Snafu.h#1 $
       */
      class Snafu : public Fiasco
      {
          int calamityLevel;

          explicit Snafu(int calamityLevelInit);
      ...
      };

      ...

      FENNEL_END_NAMESPACE

      #endif
      // End Snafu.h

Notes:

  • Standard Perforce $Id:$ tag in file header
  • Conditional compilation guards against reinclusion
  • Includes are outside the project-specific namespace block
  • All other code is inside the project-specific namespace block
  • Class documentation comment includes @author and @version tags
  • End-of-file comment

The InlineMethods page provides guidelines on use of method inlining.


Functional .cpp Files

All .cpp files containing functional code should follow the pattern below:

    /*
     * $Id: Snafu.cpp#1 $
     * ... Project boilerplate ...
     */

    #include "fennel/common/CommonPreamble.h"
    #include "fennel/device/Snafu.h"
    #include "fennel/device/Awol.h"

    FENNEL_BEGIN_CPPFILE("$Id: Snafu.cpp#1 $");

    Snafu::Snafu(int calamityLevelInit)
    {
        calamityLevel = calamityLevelInit;
    }

    ...

    FENNEL_END_CPPFILE("$Id: Snafu.cpp #1 $");
    // End Snafu.cpp

Notes:

  • Standard Perforce $Id:$ tag in file header
  • First include is always project-specific preamble
  • Second include should usually be matching header file; this helps to catch problems with implicit header dependencies
  • Other includes follow
  • All functional code is enclosed by project-specific BEGIN/END_CPPFILE lines; in the future we can use the Perforce $Id:$ tag expansions to identify file versions in assertions.
  • End-of-file comment

Test .cpp Files

Test code follows the same pattern as functional code, except that it is not included in the project namespace. Instead, it issues a using directive to import the project namespace:

    /*
     * $Id: SnafuTest.cpp#1 $
     * ... Project boilerplate ...
     */

    #include "fennel/common/CommonPreamble.h"
    #include "fennel/device/Snafu.h"
    #include "fennel/test/TestBase.h"

    using namespace fennel;

    class SnafuTest : public TestBase
    {
        void testMurphysLaw();

    public:
        explicit SnafuTest()
        {
            FENNEL_UNIT_TEST_CASE(SnafuTest,testMurphysLaw);
        }
    }

    ...

    FENNEL_UNIT_TEST_SUITE(SnafuTest);

    // End SnafuTest.cpp

TBD: rationale for this setup, and whether it's possible to introduce a test namespace.


Documentation Comments

Use of all documentation constructs recognized by doxygen is encouraged, but wherever an equivalent Javadoc construct exists, use that instead (e.g. use /** instead of //! to introduce a doc comment).

When inserting a reference to the SQL standard specification from a comment, use this convention.


Idioms

Eigenbase C++ code contains a number of common idioms.

  • Always prefix constructors with the explicit keyword unless you're sure you want implicit conversions.
  • A constructor parameter matching member variable foo should be called fooInit; don't use this->foo because it's not possible to use that pattern for reference initialization. (This is different from Java.) See Snafu example earlier in this document.
  • Use const wherever possible.
  • Follow the C99 standard when declaring variables with sized integer types (e.g. uint16_t, int64_t).
  • Pointers vs. references: use references for addresses that can't change and can't be NULL. Compiler optimizers are allowed to take advantage of this information. Use pointers for anything else.
  • Use automatic memory management such as boost shared_ptr and STL vector wherever possible. If you find yourself needing explicit delete statements, in most cases it means you're doing something wrong.
  • Avoid declaring constants at namespace scope unless they are truly global; most constants should be declared inside of classes or subnamespaces instead. Likewise for functions. Enums declared at namespace scope should use a prefixing convention for enum value names.

Assertions

  • Use the standard assert macro for assertions that should only be enabled in debug builds. These will not be compiled into optimized builds, so assert is useful for performance-sensitive code.
  • Use the Fennel-specific permAssert macro for assertions that should be enabled even in optimized builds. In code that is not performance-sensitive, it is preferable to use permAssert because it results in better field diagnostics in case of an internal error.

TBD

  • Tracing
Product Documentation