Effective C++
C++ Basic
C++ Union
- C
- Object Oriented C++
- Template C++
- STL
- TR1 - Boost
Using const,enum,inline instead of #define
- constant:using const or enum
- static int constant can not have in-class definition
- using enum hack:
enum { ConstNum = 5 };
- using enum hack:
- static int constant can not have in-class definition
- function macros:using inline function
Using const whenever possible
- bitwise constness: c++ const
- logical constness: mutable field
- call const function in non-const override functin, to avoid code redundant
Make sure init before use
- in construct function:
- using member init list instead of assignment inside function
- order by class-field-define-order in init list
- using static object in-function instead of global static object
- return reference of static local object
Constructor,Destructor, Assignment op
Silent functions in class
- default construction
- default copy construction
- operator=
- destruction
- explicitly use silent functions
- = default
Explicitly delete silent functions
- make private
- make delete
- move private or delete to a base class and private extend
Virtual destructors in polymorphic
- use virtual destruction in polymorphic base class
Non-throw destructors
- handle exceptions out of destruction
- abort when destruction meet exceptions
- ignore exceptions in destruction
No virtual call in construction and destruction
- in construction or destruction, virtual call can not goto derived class
Operator= return *this
- return *this in operator= to support multi =
Operator= handle self-assignment
- make sure good condition when self-assignment
Deep copy when copy
- copy construction
- call base copy construction
- operator=
- call base operator=
- do not call copy construction in operator=, or otherwise
Resource Management
Using resource-managing class
- using RAII class
- new resource when construction
- delete resource when destruction
- using smart pointers
Copying resource-managing class
- disable copying: unique ptr
- reference count: shared ptr
- deep copy resource
- move raw resource
Access raw in resource-managing class
- implict cast: use operator(), can be unsafe
- explict cast: use get(), more safer
Same form in new and delete
- new and delete
- new[] and delete[]
Standalone statement when smart pointers
- give new resource to smart pointer in one statement
- using make_shared, though it will keep reference count when having weak ptr
- construct smart pointer in standalone statement
- to avoid other part of statement has exceptions
Design
Make interface to easy use
- make new type or enum,static or const value,to make use correctly
Design class as type
- does a new type is really needed
- consider using non-member to replace a simple derived class
Pass by const reference instead of value
- consider pass by const reference in all place
- pass by value when standard types or function object
Dont return reference
- do not return reference of stack or heap value
Make data member private
- public data member expose the implement details
- when change public,all user must be changed
- when change protected,all derived must be changed
Non-member instead of member function
- non-member function can only use public interface, and keep the encapsulation
Non-member function when type conversion
- member function can not conversion the caller's type, while non-member function can
Non-throw swap
- using std::swap
- using std::swap in member swap
- using member swap in non-member swap
Implementation
Postpone variable definitions
- avoid early returns case no-use variable
- consider re-construction or keep the variable to operator=
Consider casting
- dynamic cast is low efficiency
- C cast:
- (T)exp
- T(exp)
- C++ cast:
- const cast
- dynamic cast
- static cast
- reinterpret cast
Avoid return handles of object internals
- when return handles of object internals, not only the function is const, also the return is const
- const InternalHandle func() const
Strive for exception safe
- exception safe:
- when exception, no memery leak, no fake state
- exception safe level:
- base exception safe: when exception, no memery leak, no fake state
- force exception safe: when exception, function is full completed or none completed
- copy and swap
- nothrow exception safe: no exception
Inlining
- inline is an advice, not a request
- when inline function changed, all dependence file must be re-compile
- when non-inline function changed, only need to re-link
Compilation dependency
- only declare class in classfwd.h, and define those in class.h
- class declare no change, only change class definition
- handle class: implementation pointer to implementation class
- handle class no change, only change implementation class
- additional memory resource management
- interface class: vptr to virtual function
- base class no change, only change derived class
- addition virtual table cost
Inheritance and OOP
Public inheritance means is-a
- make sure public inheritance means is-a relationship
- not has-a relationship
- not implement-of relationship
Avoid hiding base class through overwrite
- the same name in child class will hide those in base class, though parameters are different
- using BaseClass::function for not hiding
- BaseClass::function directly for using once
Interface extend and implementation extend
- pure virtual: interface extend
- impure virtual: interface extand and default implementation
- if no same name, using default implementation
- if has same name, hide the default implementation
- non-virtual: implementation extend
- will hide implementation if the same name in child
Alternative virtual
- template method
- template method has implementation extend, which can be final
- call virtual method which has default implementation, also can be overriden
- strategy pattern
- using function ptr
- using std::function
Never redefine non-virtual from base class
- base class implementation will be hiden
- also non-virtual function is statically bound, which means, using base class ptr or reference will call the base version
Never redefine default parameters
- virtual function is dynamically bound, while default parameter is statically bound
- which means, virtual function is about the dynamical type, and default parameter is about static type
- alternative implementation: template method
- non-virtual function to override default parameter
- call virtuall function to core implementation
Composition means has-a or implement-of
- composition is different from public inheritance
- has-a
- implement-of: using public interface to implement new feature
- ex, using list to implement set
Private inheritance means implement-of
- when implement-of is using protected member, consider private inheritance
Multiple inheritance
- virtual inheritance to handle diamond inheritance
- only use multiple inheritance when implement-of
- multiple implement interface class
- multiple implement private inheritance
Template & Generic Programming
Implicit interface and compile-time polymoriphism
- class inheritance and class template both support interface and ploymoriphism
- class inheritance is explicit support
- class template is implicit support
Using typename
- using typename means it is a type not others
- typename Class::Type_t
Templatized base class
- using template class as base class:
- template class Child: public Base
- call function in base tempalte class space:
- just simple func() won't work
- force this->func()
- force using Base::func
- force Base::func()
Template Parameter
- non-type template parameter change to function parameter, to reduce code size
- type template parameter using shared implementation to reduce code size
- in base class
- in non-member function
Member function template
- template++Class(U)
- used in construction
- used in copy construction or operator=
- default version is still needed++
Non-member function to cast
- member function can not conversion the caller's type, while non-member function can
Traits class
- using traits class to only handle types in different template specializing
Meta programming
- get result when compiling
- make sure unit is aligned
- simplify expression computation
- implement strategy pattern
New & Delete
- new handler
- when operator new failed of OOM, will call new handler
- using set_new_handler to set, usually return abort or exit
- new (std::throw)
- common new throw bad_alloc when failed
- nonthrow-new return nullptr when failled
- though opreator new wont throw, constructor will throw exception either
- why self-defined operator new and delete
- for debug or stats
- for long-term program or short-term program, big-block or tiny-block to accelate
- which standard new and delete are for common use
- self-defined operator new:
static void* operator new (std::size_t) throw (std::bad_alloc);
- handle size is not equal to class size
- allocate memory in a while loop
- call new_handler when failed
- return size-1 when ask for size-0 memory
- self-defined operator delete:
static void operator delete (void*) throw();
- handle size is not equal to class size
- self-defined placement new and delete
static void* operator new (std::size_t, void*) throw (std::bad_alloc);
static void operator delete (void*, void*) throw();
- self-define both at the same time
- do not overwrite the standard new and delete
- explict define standard new and delete in base class
- add using BaseClass:: operator new/delete in child class if you want to use the standard one
Miscellany
- TR1 是一份规范文档,Boost 则是这个规范的实现,最终会并入 C++ 标准库中