Update CodingStyle document

This commit is contained in:
Vinnie Falco
2013-06-04 07:07:09 -07:00
parent 97b6260c9a
commit d81345d8f6

View File

@@ -6,31 +6,37 @@ Coding standards used here are extreme strict and consistent. The style
evolved gradually over the years, incorporating generally acknowledged evolved gradually over the years, incorporating generally acknowledged
best-practice C++ advice, experience, and personal preference. best-practice C++ advice, experience, and personal preference.
## D.R.Y.: Don't Repeat Yourself! ## Don't Repeat Yourself!
The [Don't Repeat Yourself][1] principle summarises the essence of what it The [Don't Repeat Yourself][1] principle summarises the essence of what it
means to write good code, in all languages, at all levels. means to write good code, in all languages, at all levels.
## Formatting ## Formatting
* No tab characters! The goal of source code formatting should always be to make things as easy to
* Tabs are 4 spaces! read as possible. White space is used to guide the eye so that details are not
overlooked. Blank lines are used to separate code into "paragraphs."
* No tab characters please.
* Tab stops are set to 4 spaces.
* Braces are indented in the [Allman style][2]. * Braces are indented in the [Allman style][2].
* Always put a space before and after all binary operators, especially * Always place a space before and after all binary operators,
the assignment `operator=`! especially assignments (`operator=`).
* The `!` operator should always be followed by a space. * The `!` operator should always be followed by a space.
* The `~` operator should be preceded by a space, but not followed by one. * The `~` operator should be preceded by a space, but not followed by one.
* The `++` and `--` operators should have no spaces between the operator and its * The `++` and `--` operators should have no spaces between the operator and
operand. the operand.
* Never put a space before a comma. Always put a space after a comma. * A space never appears before a comma, and always appears after a comma.
* Always put a space before an open parenthesis! (One exception to this is if * Always place a space before an opening parenthesis. One exception is if
you've got a pair of empty parentheses) the parentheses are empty.
* Don't put spaces after a parenthesis. A typical member function call might * Don't put spaces after a parenthesis. A typical member function call might
look like this: `foobar (1, 2, 3);` look like this: `foobar (1, 2, 3);`
* In general, leave a blank line before an `if` statement. * In general, leave a blank line before an `if` statement.
* In general, leave a blank line after a closing brace `}`. * In general, leave a blank line after a closing brace `}`.
* Do not place code or comments on the same line as any opening or
closing brace.
* Do not write `if` statements all-on-one-line. The exception to this is when * Do not write `if` statements all-on-one-line. The exception to this is when
you've got a sequence of similar if statements, and are aligning them all you've got a sequence of similar `if` statements, and are aligning them all
vertically to highlight their similarities. vertically to highlight their similarities.
* In an `if-else` statement, if you surround one half of the statement with * In an `if-else` statement, if you surround one half of the statement with
braces, you also need to put braces around the other half, to match. braces, you also need to put braces around the other half, to match.
@@ -46,7 +52,7 @@ means to write good code, in all languages, at all levels.
and write the type name again, to make it quite clear what's going on, and and write the type name again, to make it quite clear what's going on, and
avoid the danger of missing out any vital asterisks. avoid the danger of missing out any vital asterisks.
* The previous point also applies to references, so always put the `&` next to * The previous point also applies to references, so always put the `&` next to
the type rather than the variable, e.g. "void foo (const Thing& thing)". And the type rather than the variable, e.g. `void foo (Thing const& thing)`. And
don't put a space on both sides of the `*` or `&` - always put a space after don't put a space on both sides of the `*` or `&` - always put a space after
it, but never before it. it, but never before it.
* The word `const` should be placed to the right of the thing that it modifies, * The word `const` should be placed to the right of the thing that it modifies,
@@ -58,14 +64,14 @@ means to write good code, in all languages, at all levels.
## Naming conventions ## Naming conventions
* Member variables and method names are written with camel-case, and never begin * Member variables and method names are written with camel-case, and never
with a capital letter. begin with a capital letter.
* Class names are also written in camel-case, but always begin with a capital * Class names are also written in camel-case, but always begin with a capital
letter. letter.
* For global variables... well, you shouldn't have any, so it doesn't matter. * For global variables... well, you shouldn't have any, so it doesn't matter.
* Class data members begin with `m_`, static data members begin with `s_`. Global * Class data members begin with `m_`, static data members begin with `s_`.
variables begin with `g_`. This is so the scope of the corresponding declaration Global variables begin with `g_`. This is so the scope of the corresponding
can be easily determined. declaration can be easily determined.
* Avoid underscores in your names, especially leading or trailing underscores. * Avoid underscores in your names, especially leading or trailing underscores.
In particular, leading underscores should be avoided, as these are often used In particular, leading underscores should be avoided, as these are often used
in standard library code, so to use them in your own code looks quite jarring. in standard library code, so to use them in your own code looks quite jarring.
@@ -73,38 +79,40 @@ means to write good code, in all languages, at all levels.
with underscores to separate the words. And obviously make sure that its name with underscores to separate the words. And obviously make sure that its name
is unlikely to clash with symbols used in other libraries or 3rd party code. is unlikely to clash with symbols used in other libraries or 3rd party code.
## Types, const-correctness, etc ## Types, const-correctness
* If a method can (and should!) be const, make it const! * If a method can (and should!) be const, make it const!
* If a method definitely doesn't throw an exception (be careful!), mark it as * If a method definitely doesn't throw an exception (be careful!), mark it as
`noexcept` `noexcept`
* When returning a temporary object, e.g. a String, the returned object should be * When returning a temporary object, e.g. a String, the returned object should
non-const, so that if the class has a C++11 move operator, it can be used. be non-const, so that if the class has a C++11 move operator, it can be used.
* If a local variable can be const, then make it const! * If a local variable can be const, then make it const!
* Remember that pointers can be const as well as primitives - for example, if you * Remember that pointers can be const as well as primitives; For example, if
have a char pointer whose contents are going to be altered, you may still be you have a `char*` whose contents are going to be altered, you may still be
able to make the pointer itself const, e.g. `char* const foobar = getFoobar();`. able to make the pointer itself const, e.g. `char* const foobar = getFoobar();`.
* Do not declare all your local variables at the top of a function or method * Do not declare all your local variables at the top of a function or method
(i.e. in the old-fashioned C-style). Declare them at the last possible moment, (i.e. in the old-fashioned C-style). Declare them at the last possible moment,
and give them as small a scope as possible. and give them as small a scope as possible.
* Object parameters should be passed as const references wherever possible. Only * Object parameters should be passed as `const&` wherever possible. Only
pass a parameter as a copy-by-value object if you really need to mutate a local pass a parameter as a copy-by-value object if you really need to mutate
copy inside the method, and if making a local copy inside the method would be a local copy inside the method, and if making a local copy inside the method
difficult. would be difficult.
* Use portable `for()` loop variable scoping (i.e. do not have multiple for loops * Use portable `for()` loop variable scoping (i.e. do not have multiple for
in the same scope that each re-declare the same variable name, as this fails on loops in the same scope that each re-declare the same variable name, as
older compilers) this fails on older compilers)
* When you're testing a pointer to see if it's null, never write `if (myPointer)`. * When you're testing a pointer to see if it's null, never write
Always avoid that implicit cast-to-bool by writing it more fully: `if (myPointer)`. Always avoid that implicit cast-to-bool by writing it more
`if (myPointer != nullptr)`. And likewise, never ever write `if (! myPointer)`, fully: `if (myPointer != nullptr)`. And likewise, never ever write
instead always write `if (myPointer == null)`. It is more readable that way. `if (! myPointer)`, instead always write `if (myPointer == nullptr)`.
It is more readable that way.
* Avoid C-style casts except when converting between primitive numeric types. * Avoid C-style casts except when converting between primitive numeric types.
Some people would say "avoid C-style casts altogether", but `static_cast` is Some people would say "avoid C-style casts altogether", but `static_cast` is
a bit unreadable when you just want to cast an `int` to a `float`. But whenever a bit unreadable when you just want to cast an `int` to a `float`. But
a pointer is involved, or a non-primitive object, always use `static_cast`. whenever a pointer is involved, or a non-primitive object, always use
And when you're reinterpreting data, always use `reinterpret_cast`. `static_cast`. And when you're reinterpreting data, always use
* Until C++ gets a universal 64-bit primitive type (part of the C++11 standard), `reinterpret_cast`.
it's best to stick to the int64 and uint64 typedefs. * Until C++ gets a universal 64-bit primitive type (part of the C++11
standard), it's best to stick to the `int64` and `uint64` typedefs.
## Object lifetime and ownership ## Object lifetime and ownership
@@ -116,14 +124,16 @@ means to write good code, in all languages, at all levels.
allocated on the stack rather than the heap, then always do so. allocated on the stack rather than the heap, then always do so.
* Do not ever use `new` or `malloc` to allocate a C++ array. Always use a * Do not ever use `new` or `malloc` to allocate a C++ array. Always use a
`HeapBlock` instead. `HeapBlock` instead.
* ..and just to make it doubly clear: Never use `malloc` or `calloc`. * And just to make it doubly clear: Never use `malloc` or `calloc`.
* If a parent object needs to create and own some kind of child object, always * If a parent object needs to create and own some kind of child object, always
use composition as your first choice. If that's not possible (e.g. if the child use composition as your first choice. If that's not possible (e.g. if the
needs a pointer to the parent for its constructor), then use a `ScopedPointer`. child needs a pointer to the parent for its constructor), then use a
`ScopedPointer`.
* If possible, pass an object as a reference rather than a pointer. If possible, * If possible, pass an object as a reference rather than a pointer. If possible,
make it a const reference. make it a `const` reference.
* Obviously avoid static and global values. Sometimes there's no alternative, but * Obviously avoid static and global values. Sometimes there's no alternative,
if there is an alternative, then use it, no matter how much effort it involves. but if there is an alternative, then use it, no matter how much effort it
involves.
* If allocating a local POD structure (e.g. an operating-system structure in * If allocating a local POD structure (e.g. an operating-system structure in
native code), and you need to initialise it with zeros, use the `= { 0 };` native code), and you need to initialise it with zeros, use the `= { 0 };`
syntax as your first choice for doing this. If for some reason that's not syntax as your first choice for doing this. If for some reason that's not
@@ -132,12 +142,13 @@ means to write good code, in all languages, at all levels.
## Classes ## Classes
* Declare a class's public section first, and put its constructors and destructor * Declare a class's public section first, and put its constructors and
first. Any protected items come next, and then private ones. destructor first. Any protected items come next, and then private ones.
* Preferred * Use the most restrictive access-specifier possible for each member. Prefer
positioning for any inherited classes is to put them to the right of the class `private` over `protected`, and `protected` over `public`. Don't expose
name, vertically aligned, e.g.: things unnecessarily.
* Preferred positioning for any inherited classes is to put them to the right
of the class name, vertically aligned, e.g.:
class Thing : public Foo, class Thing : public Foo,
private Bar private Bar
{ {
@@ -164,16 +175,20 @@ means to write good code, in all languages, at all levels.
## Miscellaneous ## Miscellaneous
* `goto` statements should not be used at all, even if the alternative is
more verbose code. The only exception is when implementing an algorithm in
a function as a state machine.
* Don't use macros! OK, obviously there are many situations where they're the * Don't use macros! OK, obviously there are many situations where they're the
right tool for the job, but treat them as a last resort. Certainly don't ever right tool for the job, but treat them as a last resort. Certainly don't ever
use a macro just to hold a constant value or to perform any kind of function use a macro just to hold a constant value or to perform any kind of function
that could have been done as a real inline function. And it goes without saying that could have been done as a real inline function. And it goes without saying
that you should give them names which aren't going to clash with other code. that you should give them names which aren't going to clash with other code.
And #undef them after you've used them, if possible. And `#undef` them after you've used them, if possible.
* When using the ++ or -- operators, never use post-increment if pre-increment * When using the `++` or `--` operators, never use post-increment if
could be used instead. Although it doesn't matter for primitive types, it's good pre-increment could be used instead. Although it doesn't matter for
practice to pre-increment since this can be much more efficient for more complex primitive types, it's good practice to pre-increment since this can be
objects. In particular, if you're writing a for loop, always use pre-increment, much more efficient for more complex objects. In particular, if you're
writing a for loop, always use pre-increment,
e.g. `for (int = 0; i < 10; ++i)` e.g. `for (int = 0; i < 10; ++i)`
* Never put an "else" statement after a "return"! This is well-explained in the * Never put an "else" statement after a "return"! This is well-explained in the
LLVM coding standards...and a couple of other very good pieces of advice from LLVM coding standards...and a couple of other very good pieces of advice from
@@ -181,8 +196,10 @@ means to write good code, in all languages, at all levels.
* When getting a possibly-null pointer and using it only if it's non-null, limit * When getting a possibly-null pointer and using it only if it's non-null, limit
the scope of the pointer as much as possible - e.g. Do NOT do this: the scope of the pointer as much as possible - e.g. Do NOT do this:
Foo* f = getFoo(); if (f != nullptr) f->doSomething(); Foo* f = getFoo ();
...lots of code... if (f != nullptr)
f->doSomething ();
// other code
f->doSomething (); // oops! f may be null! f->doSomething (); // oops! f may be null!
..instead, prefer to write it like this, which reduces the scope of the ..instead, prefer to write it like this, which reduces the scope of the