-
Notifications
You must be signed in to change notification settings - Fork 394
Coding Standards Part 1 Style
This style guide is more of a "where we'd like to be" than what is actually in the code. Please make all contributions fall inline with the current style of the code instead of this guide. Whitespace, indentation, and other patterns currently in use in the code can be seen from a quick peek of the source code.
- [Part 0: Automated Analysis](Coding Standards Part 0 Automated Analysis)
- [Part 1: Style](Coding Standards Part 1 Style)
- [Part 2: Performance and Safety](Coding Standards Part 2 Performance and Safety)
- [Part 3: References and Further Reading](Coding Standards Part 3 References and Further Reading)
Style guidelines are not overly strict. The important thing is that code is clear and readable with an appropriate amount of whitespace and reasonable length lines. A few best practices are also mentioned.
C++ allows for arbitrary length identifier names, so there's no reason to be terse when naming variables. Use descriptive names, and be consistent in the style
CamelCase
snake_case
are common examples. snake_case has the advantage that it can also work with spell checkers, if desired.
- Types start with capitals:
MyClass
- functions and variables start with lower case:
myMethod
- [SM] Do we want to specify a preference for my_method over myMethod? The former is probably more common now. Qt and some libs use the latter. An exclusion when the case is vital to the meaning should be allowed.
- constants are all capital:
const int PI=3.14159265358979323;
- [SM] That is more common for macros. Could be informative to readers on the other hand sometimes the constness is an implementation detail that shouldn't leak into the point of use. Also, it emphasizes the constants visually when they may be relatively unimportant:
foo( arg, ROUTINENAME )
is not lovely.
- [SM] That is more common for macros. Could be informative to readers on the other hand sometimes the constness is an implementation detail that shouldn't leak into the point of use. Also, it emphasizes the constants visually when they may be relatively unimportant:
Note that the C++ standard does not follow any of these guidelines. Everything in the standard is lowercase only.
Name private data with a m_
prefix to distinguish it from public data.
- [SM] Name decorating by storage type is needed to distinguish the data from its accessors but putting the decoration at the front of the name obscures readability. Suggest
x
for public data,x_
for private data,x()
for accessors for readability.
Name function parameters with an t_
prefix.
-
[SM] Suggest we reconsider this. Overemphasizes source of variable and sort of anti-OO in the sense that in a local scope the source of a variables is an external implementation detail.
-
[JT] I hold no real strong preference for how variables are named, just attempting to have had something to start the discussion.
class MyClass
{
public:
MyClass(int t_data)
: m_data(t_data)
{
}
int getData() const
{
return m_data;
}
private:
int m_data;
};
Tabs are not allowed, and a mixture of tabs and spaces is strictly forbidden. Modern autoindenting IDEs and editors require a consistent standard to be set.
// Good Idea
int myFunction(bool t_b)
{
if (t_b)
{
// do something
}
}
[SM] There are good arguments for both tab and space indenting. Tabs have some benefits: 1) User controls indenting they want to see in their IDE, 2) With visual indent set to 3 or above commenting out lines doesn't break indentation alignment (this is very nice!), 3) Files are slightly smaller and thus should be very slightly faster to compile.
[JT] Consistency is the most important thing here. Tabs seem to have stuck at this point, so that is where we are
Leaving them off can lead to semantic errors in the code.
// Bad Idea
// this compiles and does what you want, but can lead to confusing
// errors if close attention is not paid.
for (int i = 0; i < 15; ++i)
std::cout << i << std::endl;
// Bad Idea
// the cout is not part of the loop in this case even though it appears to be
int sum = 0;
for (int i = 0; i < 15; ++i)
++sum;
std::cout << i << std::endl;
// Good Idea
// It's clear which statements are part of the loop (or if block, or whatever)
int sum = 0;
for (int i = 0; i < 15; ++i) {
++sum;
std::cout << i << std::endl;
}
// Bad Idea
// hard to follow
if (x && y && myFunctionThatReturnsBool() && caseNumber3 && (15 > 12 || 2 < 3)) {
}
// Good Idea
// Logical grouping, easier to read
if (x && y && myFunctionThatReturnsBool()
&& caseNumber3
&& (15 > 12 || 2 < 3)) {
}
[SM] Converted code is currently unwrapped pending decision on line wrapping. Since IDEs can soft-wrap for you one option is to leave lines unwrapped and let the user control visual wrapping to make best use of their display and preferences. Wrapping lines is hard to do nicely and some editors (looking at you, emacs!) do silly things with aligning wrapped lines on function parentheses that creates a maintenance burden.
...with the member initializer list
// Bad Idea
class MyClass
{
public:
MyClass(int t_value)
{
m_value = t_value;
}
private:
int m_value;
};
// Good Idea
// C++'s memeber initializer list is unique to the language and leads to
// cleaner code and potential performance gains that other languages cannot
// match
class MyClass
{
public:
MyClass(int t_value)
: m_value(t_value)
{
}
private:
int m_value;
};
Compiler definitions and macros are replaced by the pre-processor before the compiler is ever run. This can make debugging very difficult because the debugger doesn't know where the source came from.
// Good Idea
namespace my_project {
class Constants {
public:
static const double PI = 3.14159;
}
}
// Bad Idea
#define PI 3.14159;
[AR] Certainly this is a good idea for constants, but are other uses of the preprocessor also frowned upon? What about DEBUG wrappers?
C++11 introduces nullptr
which is a special type denoting a null pointer value. This should be used instead of 0 or NULL to indicate a null pointer.
Comment blocks should use //
, not /* */
. Using //
makes it much easier to comment out a block of code while debugging.
// this function does something
int myFunc()
{
}
To comment out this function block during debugging we might do:
/*
// this function does something
int myFunc()
{
}
*/
which would be impossible if the function comment header used /* */