Guidelines for Physical Design
-
Document the interfaces so that they are usable by others;
have at least one other developer review each interface.
-
Explicitly state conditions under which behavior is undefined.
-
Be consistent about indentifier names; use either uppercase or
underscore but not both to delimit words in identfiers.
-
Be consistent about names used in the same way;
in particular adopt consistent method
names and operators for recurring design patterns such as iteration.
-
Clients should include header files providing required type definitions
directly; except for non-private inheritance, avoid relying on one header
file to include another.
-
A component x should include y.h only if x makes direct substantive
use of a class or free operator function defined in y.
-
Avoid granting (long-distance) friendship to a logical entity
defined in another component.
-
Avoid cyclic physical dependencies among components.
-
In general, avoid granting any one component license that, if also
taken by other components, would adversely impact the system as a whole.
-
Prefer modules to non-local static instances of objects, especially when:
- Direct access to the construct is needed outside a translation unit.
- The construct may not be needed during start-up or immediately
thereafter and the time to initialize the construct itself
is significant.
-
The semantics of an overloaded operator should be natural, obvious,
and intuitive to clients.
-
The syntactic properties of overloaded operators for user-defined types
should mirror the properties already defined for the fundamental types.
-
Avoid hiding a base-class function in a derived class.
-
Every object in a system should be const-correct.
-
Think twice (at least) before casting away const.
-
For functions that return an error status, an integral value of 0
should always mean success.
-
Functions that answer a yes-or-no question should be worded appropriately
(e.g., isValid) and return an int value of either 0 ("no")
or 1 ("yes").
-
Avoid declaring results returned by value from functions as const.
-
Avoid default arguments that require the construction of an
unnamed temporary object.
-
Be consistent about returning values through arguments (e.g., avoid
declaring non-const reference parameters).
-
Avoid storing the address of any argument to a function in a
location that will persist after the function terminates;
pass the address of the argument instead.
-
Whenever a parameter passes its argument by reference or pointer to
a function that neither modifies that argument nor stores its
writeable address, that parameter should be declared const.
-
Avoid declaring parameters passed by value to a function as const.
-
Consider placing parameters (except perhaps those with default
arguments) that enable modifiable access before parameters
that pass arguments by value, const reference, or const pointer.
-
Avoid granting friendship to individual functions.
-
Avoid declaring a function inline whose body produces object code that is
larger than the object code produced by the equivalent non-inline function
call itself.
-
Avoid declaring a function inline that your compiler will not generate inline.
-
Avoid using short in the interface; use int instead.
-
Avoid using unsigned in the interface; use int instead.
-
Avoid using long in the interface; assert(sizeof(int) >= 4) and
use either int or a user-defined large-integer type instead.
-
Consider using double exclusively for floating-point types used in the
interface unless there is a compelling reason to use float or long double.
-
Consider avoiding "cast" operators, especially to fundamental integral
types; instead make the conversion explicit.
-
Explicitly declare (either public or private) the constructor and
assignment operator for any class defined in a header file,
even when the default implementations are adequate.
-
In classes that do not otherwise declare virtual functions, explicitly
declare the destructor as non-virtual and define it appropriately
(either inline or out-of-line).
-
Use short instead of int in the implementation as an optimization
only when it is known to be safe to do so.
-
Consider not using unsigned even in the implementation.
-
When designing a function, component, package, or entire system,
use the simplest techniques that are effective.
-
Avoid allowing programmatic access to physical values.
-
The result of calling a const member function should not alter
any programmatically accessible value in the object.
-
Prefer object-specific over class-specific memory management.
-
Use a non-const pointer data member to hold managed objects.
-
Consider providing a way to switch between block allocations and
individual allocations of dynamic memory.
-
When implementing memory management for a completely general,
parameterized container that manages the memory for its contained
objects, assume that the parameterized type defines a copy
constructor and a destructor -- nothing more.
-
Where possible, implement templates on top of a factored reusable
void * pointer type using inline functions to reestablish type safety.