I've been involved in developing coding standards which were quite elaborate. My own experience is that it was hard to enforce if you don't have proper processes to maintain it and strategies to uphold it.
Now I'm working in, and leading, an environment even less probable to have processes and follow-up strategies in quite a while. Still I want to uphold some minimum level of respectable code. So I thought I would get good suggestions here, and we might together produce a reasonable light-weight subset of the most important coding standard practices for others to use as reference.
So, to emphasize the essence here:
What elements of a C++ coding standard are the most crucial to uphold?
Answering/voting rules
1 candidate per answer, preferably with a brief motivation.
Vote down candidates which focuses on style and subjective formatting guidelines. This is not to indicate them as unimportant, only that they are less relevant in this context.
Vote down candidates focusing on how to comment/document code. This is a larger subject which might even deserve its own post.
Vote up candidates that clearly facilitates safer code, which minimizes the risk of enigmatic bugs, which increases maintainability, etc.
Don't cast your vote in any direction on candidates you are uncertain about. Even if they sound reasonable and smart, or on the contrary "something surely nobody would use", your vote should be based on clear understanding and experience.
Curly braces for any control statement. (Thanks to own experience and reinforced by reading Code Complete v2):
Forbid
t[i]=i++;
f(i++,i);
, and so on as there is no (portable) guarantees regarding what is executed first.Always, always, always do proper data member initialization on object construction.
I ran into a problem where an object constructor was relying on some "default" initialization for its data members. Building the code under two platforms (Windows/Linux) gave different results and a hard-to-find memory bug. The result was that a data member was not initialized in the constructor, and used before it was initialized. On one platform (Linux), the compiler initialized it to what the code writer thought appropriate default. On Windows, the value was initialized to something - but garbage. On use of the data member, everything went haywire. Once the initialization was fixed - no more problem.
Use C++ casts instead of C casts
use:
static_cast
const_cast
reinterpret_cast
dynamic_cast
but never C-style casts.
How it clearly facilitates safer code, which minimizes the risk of enigmatic bugs, which increases maintainability, etc.
Each cast has limited powers. E.g., if you want to remove a const (for whatever reason),
const_cast
won't change the type at the same time (which could be a bug difficult to find).Also, this enables a reviewer to search for them and then, the coder to justify them if needed.
Know who is owner of that memory.
How it clearly facilitates safer code, which minimizes the risk of enigmatic bugs, which increases maintainability, etc.?
Not having a clear memory ownership philosophy leads to interesting bugs or memory leaks, and time lost wondering if the char * returned by this function should be deallocated by the user, or not, or given back to a special deallocation function, etc..
As much as possible, the function/object allocating the memory must be the function/object deallocating it.
Premature optimization is the root of all evil
Write safe and correct code first.
Then, if you have performance problems, and if your profiler told you the code is slow, you can try to optimize it.
Never believe you will optimize snippets of code better than the compiler.
When looking for optimizations, study the algorithms used, and potentially better alternatives.
How it clearly facilitates safer code, which minimizes the risk of enigmatic bugs, which increases maintainability, etc.?
Usually, "optimized" (or supposedly optimized) code is a lot less clearer, and tend to express itself through raw, near-the-machine way, instead of a more business-oriented way. Some optimizations rely of switchs, if, etc., and then will be more difficult to test because of multiple code paths.
And of course, optimization before profiling often lead to zero performance gain.