Most of this is taken from the books
Be sure your code compiles at the highest compiler warning level. eg.
.
-Wall -ansi -pedantic -Werror
To turn of warnings coming from headers you can not change use (Unfortunately this is for VC2005 and does not work for g++.) :
.
#pragma warning(push) // disable for this header only
#pragma warning(pop) // restore original warning level
.
#pragma warning(disable:4512) #pragma warning(disable:4180)
#include <boost/lambda/lambda.hpp>
* C++ : “resource acquisition is initialization” (RAII) * When allocating a raw resource, immediately pass it to an owning object: Prefer to hold dynamically allocated resources via smart pointers instead of raw pointers. Perform every explicit resource allocation (e.g., new) in its own statement that immediately gives the allocated resource to a manager object (e.g., shared_ptr). If you use a Smart Pointer you are TAKING OWNERSHIP of the object! ' (→ dont use smart pointers for resources YOU did not allocate. The Resource WILL be deleted when your Smart Pointer disappears). * Never allocate more than one resource in a single statement. (Exceptions!) * To avoid unwanted copies make all objects extend boost::noncopyable by default * Be conscious of copy construction and assignment the compiler-generated versions probably won't be correct. * When using shared_ptr be wary of 'circular references (use weak_ptr to avoid). ====== Coding Style ====== ===== Avoid Macros ===== * Except for Include Guards and Conditional Compilation! ===== Static Type Checking ===== * Prefer to write code that uses the compiler to check for invariants during compilation use const avoid void* avoid unsafe casts
* Use const whereever possible * When a const member function of a class legitimately needs to modify a member variable declare that member variable mutable * Never cast away const except to call a const-incorrect function * Avoid const pass-by-value function parameters in function declarations (they are confusing and useless to the reader of the header file). Const pass-by-value function parameters can (and should) be used in the functions definition however!
* Avoid Magic Numbers, use constants
.
class Muh { static const int DEFAULT_COW_SIZE = 400; };
* Replace complicated computational flows with functions easier to Read easier to Test * Avoid long functions and deep nesting Every function should be a coherent unit of work bearing a suggestive name Give one function one responsibility Don't repeat yourself: Prefer a named function over repeated similar code snippets (Code Smells!) Prefer &&: Avoid nested consecutive ifs where an && condition will do. Prefer automatic cleanup via destructors over Try blocks Prefer algorithms: They're flatter than loops (http://www.cplusplus.com/reference/algorithm/) Don't switch on type tags. Prefer polymorphic functions ===== Avoid Cyclic Dependencies ===== * Good Design * Forward Declarations! (see the Chapter in “Effective C++” ) ===== Make Headers self-sufficient ===== * Ensure that each header you write is compilable standalone, by having it include any headers its contents depend upon. * But don't include headers that you don't need * Make sure each Header has an INCLUDE GUARD! Use a unique guard name
. #ifndef FOO_H_INCLUDED_ #define FOO_H_INCLUDED_ contents of the file #endif ====== Functions and Operators ====== ===== Don't write code that depends on the order of evaluation of function arguments ===== The order in which arguments of a function are evaluated is unspecified, so don't rely on a specific ordering. Example: . void Transmogrify( int, int ); int count = 5; Transmogrify( ++count, ++count ); order of evaluation unknown!
The cure is simple: use named objects to enforce order of evaluation!
==Parameter Passing== * Don't use C-style varargs! Input Parameters' * Always const-qualify all pointers or references to input-only parameters. * Prefer taking inputs of primitive types (e.g., char, float) and value objects that are cheap to copy (e.g., Point, complex<float>) by val. * Prefer taking inputs of other user-defined types by reference to const. * Consider pass-by-value instead of reference if the function requires a copy of its argument 'In/Out Parameters * Prefer passing by (smart) pointer if the argument is optional (so callers can pass null as a “not available” or “don't care” value) or if the function stores a copy of the pointer or otherwise manipulates ownership of the argument. * Prefer passing by reference if the argument is required and the function won't store a pointer to it or otherwise affect its ownership. This states that the argument is required and makes the caller responsible for providing a valid object.
Overload operators only for good reason, and preserve natural semantics; if that's difficult, you might be misusing operator overloading.
“The most important single aspect of software development is to be clear about what you are trying to build.” –Bjarne Stroustrup
* Has a public destructor, copy constructor, and assignment with value semantics. (* Has no virtual functions (including the destructor).) * Is intended to be used as a concrete class, not as a base class. * Is usually instantiated on the stack or as a directly held membr of another class.
Base classes are the building blocks of class hierarchies. * Has a destructor that is public and virtual or else protected and nonvirtual * Has a nonpublic copy constructor and assignment operator (use boost::noncopyable!) * Establishes interfaces through virtual functions. * Is usually instantiated dynamically on the heap and used via a (smart) pointer.
Are templates that carry information about types.
Are fragments of pluggable behavior.
They exhibit an unusual mix of value and reference semantics: They are thrown by value but should be caught by reference.
Divide and conquer: Small classes are easier to write, get right, test, and use. They are also more likely to be usable in a variety of situations. Prefer such small classes that embody simple concepts instead of kitchen-sink classes that try to implement many and/or complex concepts.
Avoid inheritance taxes: Inheritance is the second-tightest coupling relationship in C++, second only to friendship. Tight coupling is undesirable and should be avoided where possible. Therefore, prefer composition to inheritance unless you know that the latter truly benefits your design.
BUT: Do use public inheritance to model substitutability!!
Abstract interfaces help you focus on getting an abstraction right without muddling it with implementation or state management details. Prefer to design hierarchies that implement abstract interfaces that model abstract concepts.
Follow the Dependency Inversion Principle (DIP): * High-level modules should not depend upon low-level modules. Rather, both should depend upon abstractions. * Abstractions should not depend upon details. Rather, details should depend upon abstractions. =⇒ Hierarchies should be rooted in abstract classes, not concrete classes. Put another way: Push policy up and implementation down! * Be wary about using multiple inheritance of classes that are not abstract interfaces
When overriding a virtual function, preserve substitutability; in particular, observe the function's pre- and post-conditions in the base class. Don't change default arguments of virtual functions. Prefer explicitly redeclaring overrides as virtual.
Think twice before providing implicit conversions to and from the types you define, and prefer to rely on explicit conversions (explicit constructors and named conversion functions).
Implicit conversions have two main problems:
Implicitly converting constructors (constructors that can be called with one argument and are not declared explicit) interact poorly with overloading and foster invisible temporary objects that pop up all over. –>
. class Widget {
. explicit Widget( unsigned int widgetizationFactor ); explicit Widget( const char* name, const Widget* other = 0 );
};
. const char* toCharPointer() const;
Keep data members private. Only in the case of simple C-style struct types that aggregate a bunch of values but don't pretend to encapsulate or provide behavior, make all data members public. Avoid mixes of public and nonpublic data, which almost always signal a muddled design.
Avoid returning handles to internal data managed by your class, so clients won't uncontrollably modify state that your object thinks it owns. * If you absolutely _have_ to return references to internal (private) data, at least return const references!
Member variables are always initialized in the order they are declared in the class definition; the order in which you write them in the constructor initialization list is ignored. Make sure the constructor code doesn't confusingly specify a different order.
==Prefer initialization to assignment in constructors == In constructors, using initialization instead of assignment to set member variables prevents needless run-time work and takes the same amount of typing.
== Avoid calling virtual functions in constructors and destructors== Virtual functions dont always behave virtually: Inside constructors and destructors, they don't. Worse, any direct or indirect call to an unimplemented pure virtual function from a constructor or destructor results in undefined behavior. If your design wants virtual dispatch into a derived class from a base class constructor or destructor, you need other techniques such as post-constructors.
. 'In C++, a complete object is constructed one base class at a time. Say we have a base class B and a class D derived from B. When constructing a D object, while executing B's constructor, the dynamic type of the object under construction is B. In particular, a call to a virtual function B::Fun will hit B's definition of Fun, regardless of whether D overrides it or not.'
If you really need post-construction its easiest to have your object created by a factory and call the post construction method before returning the object!
If deletion through a pointer to a base Base should be allowed, then Base's destructor must be public and virtual. Otherwise, it should be protected and nonvirtual.
Therefore: Always write a destructor for a base class, because the implicitly generated one is public and nonvirtual!!
Never allow an error to be reported from a destructor, a resource deallocation function (e.g., operator delete), or a swap function. Specifically, types whose destructors may throw an exception are flatly forbidden from use with the C++ standard library.
If you define any of the copy constructor, copy assignment operator, or destructor, you might need to define one or both of the others.
A common mistake is to forget to think about copy and assignment semantics when defining a class → Ensure that your class provides sensible copying:
Be sure when which type of assignment is used. As a guideline: if a variable already exists an assignment uses the operator= method, otherwise a constructor is used.
MyClass x(); //constructor MyClass y(x); //copy constructor x = MyClass(); //operator=