C++ Coding Style

Low Zhen Lin <[email protected]> Sun, 21 Dec 2003 00:03:55 +0800
Newsgroups gmane.linux.zynot.general,gmane.linux.zynot.devel
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Since we are about to begin coding, I thought it might be wise to
declare the style conventions.

Here are mine:

4 spaces per tab.

'{' on a new line, flush with the previous line:

~    int main()
~    {

... except when hugged:

~    } else {

~    } else if ... {

~    } catch (...) {

... or in small initialisers:

~    int arr[4] = { 0, 1, 2, 3 };
~    uuid id = { 0xDEADBEEF, 0x0F00, 0x0BA2, 0x1337, 0xBABA, 0xBEEFDEAD };

... where the insides are padded with one space on both ends.

'(' immediately after function names and constructors (and macros -
macros REQUIRE this rule):

~    int main(int argc, const char* argv[]);

~    std::string s("Hello World!");

~    exit(-1);

~    sizeof(int) // sizeof is function-like.

... one space after branch control:

~    if (i < 0)

~    while (true)

... none in these:

~    return 0;

~    throw *new ArrayIndexOutOfBoundsException;

~    a = new Object;

'*' attached to typename, no spaces in declaration:

~    const char* cstring;
~    int (*pfunc)(int, int);

... one space after for casting:

~    (int *)malloc(sizeof(int[128]));
~    (void *)main;

... no spaces in between '*':

~    const char** argv;
~    (void **)vtable

... no spaces after for dereferencing:

~    *(array_start + index);

~    return (*a < *b);

... none for invoking functions:

~    pfunc(); // Not compatible with MSVC++

... function pointers:

~    RetType (*TypeName)(ParamType, ParamType)

'[]' attached to identifier, no spaces, always:

~    int array[16];
~    int matrix[8][8];
~    int 3dSpace[4][4][4];

'<' after 'template', space in between:

~    template <typename T> T* allocate();

Even if it is 'template <>', retain it:

~    template <> int getFib<1>() { return 1; }
~    template <> int getFib<0>() { return 0; }

'<' after template name, no space in between:
~    template <int N> int getFib() { return getFib<N-1>() +
getFib<N-2>(); }

CamelCasing for type names, smallFirst for instance names:

~    RadioButton radioButton;

~    void onClick(double, double);
~    // onClick is an instance of void (*)(double, double)

Space after ',', always:

~    int arr[] = { 0, 1, 2, 3 };
~    printf("%s", cstring);

Labels at previous indent level:

~    int main()
~    {
~        int i = 0;
~    LoopTop:
~        cout << "i = " << i << endl;
~        i++;
~        if (i < 16)
~            goto LoopTop;
~        return 0;
~    }

... except when the label marks off sections of code,
~           has special meaning,
~           or is at the top of a block:

~    int main()
~    {
~        Top:
~            cout << "At Top!" << endl;
~        Bottom:
~            cout << "At Bottom!" << endl;
~            return 0;
~    }

~    switch (choice)
~    {
~        case 0:
~            cout << "This menu system is a figment of your
imagination." << endl;
~            break;
~        case 1:
~        case 2:
~        case 3:
~        case 4:
~        case 5:
~            cout << "Pick a bigger number, nitwit!" << endl;
~            break;
~        case 6:
~        case 7:
~        case 8:
~        case 9:
~            cout << "You have selected " << choice << ". Have a nice
day." << endl;
~            break;
~        default:
~            cout << "Hmm, you have a queer number pad." << endl;
~    }

~    class Object
~    {
~        public:
~            explicit Object();
~        protected:
~            unsigned int refCount;
~        private:
~            Object(Object&) { }
~    };

When there is only one statement where there is normally a block, put
the statement on the same line as the block-preceding line:

~    switch (choice)
~    {
~        case 5: cout << "Hello!" << endl;
~        case 4: cout << "Hello!" << endl;
~        case 3: cout << "Hello!" << endl;
~        case 2: cout << "Hello!" << endl;
~        case 1: cout << "Hello!" << endl;
~        case 0: break;
~        default:
~            for (int i = 0; i < choice; i++) cout << "Hello!" << endl;
~            break;
~    }

~         if (o.isa(Class(String)) cout << "I got a String!" << endl;
~    else if (o.isa(Class(Number)) cout << "I got a Number!" << endl;
~    else if (o.isa(Class(Object)) cout << "I got an Object!" << endl;
~    else cout << "I got something wierd." << endl;

Note that the 'if' lines up. When feasible, line up code to be neater:

~       int i = 0;
~      char c = '\0';
~    double d = 0.0;
~     void* p = 0;

Local variable declaration at the top of the function body, split into
groups, seperate groups by a blank line:

~    int arr[128] = { 0 };
~    int index = 0;
~    // BLANK LINE
~    char string[] = "String";
~    char* pChar = string;
~    // BLANK LINE
~    node* rootNode = tree.getRoot();
~    node* parentNode = 0;
~    node* currentNode = root;

Prefer inline functions or templates to macros for code.
Prefer macros to inline functions or templates for simple expressions.
Always use inline functions and/or templates when parameters are
evaluated more than once.

Avoid 'using namespace' statements in headers.

'.c++' for C++ source code. 'cpp' is the C preprocessor, damnit! 'cxx'
is for badly designed filesystems. 'cc' is the C compiler, not the C++
compiler. 'C' is indistinguishable from 'c' on Mac OS X (HFS+) and
Windows and other 'user friendly' OSes.
'.h' for C and C++ headers. cpp thinks they're the same.

C++ class files and their headers go into the same directory.
One class per header.
Directory structure reflecting namespace:

~    // to get Siphonophora::ComponentKit::Core::Object
~    #include <Siphonophora/ComponentKit/Core/Object.h>

'I' before interface names, unless an adjective:

~    class ITaskManager;
~    class Copyable;

Object classes have nouns for names:

~    class Toy;
~    class Goo;
~    class BlueGoo;

Functions have verbs for names:

~    size_t getSize();
~    void rebalanceTree();
~    template <typename T> T* allocate();

British spelling:

~    ColourPicker colourPicker;

Metric units (preferred, but provide imperial for locale compatibility):

~    double getLengthInCM();
~    double getLengthInInches();
~    length getLength() { return *new Length(this->getLengthInCM(),
Length::cm); }

Always use new-style casts:

~    static_cast<int *>malloc(sizeof(int[128]));
~    const_cast<char *>argv[0]; // Avoid!
~    dynamic_cast<Object>anUnknownObject; // Surround with try catch!
~    reinterpret_cast<unsigned int>aFloat; // Avoid! But a good way to
access the representation of an object in memory.

No publicly accessible variables. Use set/get instead. (Yes, I know it
is slower, but - you can inline it, and the object is notified if
someone changes the variable. Also more flexible about storage of the
variable.)

Those are my eccentricities/coding style. Feel free to argue against -
but be sure to rationalise. We're aiming for code readability, not
file size or character count or anything concrete like that.

Followups to zynot-dev.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQE/5HLqv+6a/MPcjnERAorTAJ97CA3pxhErwdFnLOaBVJ6ftygmUACgjmi5
1xUqswDs3nrk2d2H9TpsUpA=
=92jA
-----END PGP SIGNATURE-----