C++ Language-Specific Rules - Part 3: Advanced Topics
Based on Scott Meyers' Effective C++ series and C++ Core Guidelines
Part of a multi-file C++ rules series:
- lang-cpp-basics.md - Formatting, language basics, constructors, RAII
- lang-cpp-design.md - Design, declarations, and implementations
- lang-cpp-advanced.md (this file) - OOP, templates, and advanced topics
- lang-cpp-modern.md - Modern C++ (C++11/14/17/20)
- lang-cpp-guidelines.md - C++ Core Guidelines
- lang-cpp-reference.md - Quick reference checklist
Chapter 6: Inheritance and Object-Oriented Design
Item 32: Make Sure Public Inheritance Models "Is-a"
Principle: Public inheritance means "is-a". Everything applicable to base class must apply to derived class.
class Bird {
public:
virtual void fly(); // Birds can fly
};
class Penguin: public Bird {
// Penguins are birds but can't fly!
// This inheritance is wrong!
};
// BETTER - more accurate hierarchy
class Bird { ... };
class FlyingBird: public Bird {
public:
virtual void fly();
};
class Penguin: public Bird {
// No fly function
};
```text
**Square-Rectangle problem:**
```cpp
// Mathematically, square is-a rectangle
class Rectangle {
public:
virtual void setHeight(int newHeight);
virtual void setWidth(int newWidth);
virtual int height() const;
virtual int width() const;
};
class Square: public Rectangle { ... };
void makeBigger(Rectangle& r) {
int oldHeight = r.height();
r.setWidth(r.width() + 10);
assert(r.height() == oldHeight); // Should be true for rectangles
// But fails for squares!
}
```text
### Item 33: Avoid Hiding Inherited Names
**Problem:** Derived class scope hides base class scope.
```cpp
class Base {
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
};
class Derived: public Base {
public:
virtual void mf1(); // Hides Base::mf1(int)!
void mf3(); // Hides both Base::mf3()!
void mf4();
};
Derived d;
d.mf1(); // OK - calls Derived::mf1
d.mf1(10); // ERROR! Derived::mf1 hides Base::mf1(int)
d.mf2(); // OK - calls Base::mf2
d.mf3(); // OK - calls Derived::mf3
d.mf3(5.5); // ERROR! Derived::mf3 hides Base::mf3(double)
```text
**Solutions:**
**1. Using declarations:**
```cpp
class Derived: public Base {
public:
using Base::mf1; // Make all Base::mf1 versions visible
using Base::mf3; // Make all Base::mf3 versions visible
virtual void mf1();
void mf3();
};
Derived d;
d.mf1(); // OK - calls Derived::mf1
d.mf1(10); // OK - calls Base::mf1(int)
d.mf3(); // OK - calls Derived::mf3
d.mf3(5.5); // OK - calls Base::mf3(double)
```text
**2. Forwarding functions (for selective unhiding):**
```cpp
class Derived: private Base { // Private inheritance
public:
virtual void mf1() { // Forwarding function
Base::mf1(); // Inline call to Base::mf1
}
};
Derived d;
d.mf1(); // OK - Derived::mf1 which calls Base::mf1
d.mf1(10); // ERROR - Base::mf1(int) not inherited
```text
### Item 34: Differentiate Between Inheritance of Interface and Inheritance of Implementation
**Three types of inheritance:**
**1. Pure virtual - inherit interface only:**
```cpp
class Shape {
public:
virtual void draw() const = 0; // Must be redefined by derived classes
virtual void error(const std::string& msg); // Can be redefined
int objectID() const; // Must not be redefined
};
```text
**2. Simple virtual - inherit interface + default implementation:**
```cpp
class Airport { ... };
class Airplane {
public:
virtual void fly(const Airport& destination); // Default fly behavior
};
class ModelA: public Airplane { ... }; // Uses default fly
class ModelB: public Airplane { ... }; // Uses default fly
// Later, add ModelC that SHOULD have different fly()
class ModelC: public Airplane { ... }; // Oops! Forgot to override fly()
// Uses default - probably wrong!
```text
**Better approach - separate interface from default:**
```cpp
class Airplane {
public:
virtual void fly(const Airport& destination) = 0; // Pure virtual interface
protected:
void defaultFly(const Airport& destination); // Default implementation
};
void Airplane::defaultFly(const Airport& destination) {
// Default code for flying
}
class ModelA: public Airplane {
public:
virtual void fly(const Airport& destination) {
defaultFly(destination); // Explicitly opt into default
}
};
class ModelC: public Airplane {
public:
virtual void fly(const Airport& destination); // Must provide implementation
};
```text
**3. Non-virtual - inherit interface + mandatory implementation:**
```cpp
class Shape {
public:
int objectID() const { return oid; } // Never override this!
private:
int oid;
};
```text
### Item 35: Consider Alternatives to Virtual Functions
**1. Non-Virtual Interface (NVI) Idiom:**
```cpp
class GameCharacter {
public:
int healthValue() const { // Non-virtual public interface
// Pre-logic
int retVal = doHealthValue(); // Call virtual
// Post-logic
return retVal;
}
private:
virtual int doHealthValue() const { // Virtual implementation
... // Default calculation
}
};
```text
**2. Function Pointers:**
```cpp
class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter {
public:
typedef int (*HealthCalcFunc)(const GameCharacter&);
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf)
{ }
int healthValue() const {
return healthFunc(*this);
}
private:
HealthCalcFunc healthFunc;
};
```text
**3. std::function (Modern C++):**
```cpp
class GameCharacter {
public:
typedef std::function<int (const GameCharacter&)> HealthCalcFunc;
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf)
{ }
int healthValue() const {
return healthFunc(*this);
}
private:
HealthCalcFunc healthFunc;
};
```text
**4. Strategy Pattern:**
```cpp
class GameCharacter;
class HealthCalcFunc {
public:
virtual int calc(const GameCharacter& gc) const { ... }
};
HealthCalcFunc defaultHealthCalc;
class GameCharacter {
public:
explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc)
: pHealthCalc(phcf)
{ }
int healthValue() const {
return pHealthCalc->calc(*this);
}
private:
HealthCalcFunc* pHealthCalc;
};
```text
### Item 36-40: Additional Inheritance Guidelines
**Item 36:** Never redefine an inherited non-virtual function
- Non-virtual functions are statically bound
- Redefinition leads to inconsistent behavior
**Item 37:** Never redefine a function's inherited default parameter value
- Default parameters are statically bound
- Virtual functions are dynamically bound
- Leads to confusion
**Item 38:** Model "has-a" or "is-implemented-in-terms-of" through composition
- Has-a: Car has-a Engine
- Use composition, not inheritance
**Item 39:** Use private inheritance judiciously
- Means "is-implemented-in-terms-of"
- Composition is usually better
- Use private inheritance when accessing protected members or redefining virtuals
**Item 40:** Use multiple inheritance judiciously
- Can lead to diamond problem
- Use virtual inheritance to solve it
- Virtual inheritance has costs (size, speed, initialization complexity)
- Prefer single inheritance or composition
## Chapter 7: Templates and Generic Programming
### Item 41: Understand Implicit Interfaces and Compile-Time Polymorphism
**Principle:** Templates support implicit interfaces and compile-time polymorphism, unlike classes which support explicit interfaces and runtime polymorphism.
```cpp
// Explicit interface with runtime polymorphism
class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
};
void doProcessing(Widget& w) {
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w);
temp.normalize();
temp.swap(w);
}
}
// Implicit interface with compile-time polymorphism
template<typename T>
void doProcessing(T& w) {
// Implicit interface:
// - T must support size() returning something comparable to 10
// - T must support operator!=
// - T must support copy constructor
// - T must support normalize()
// - T must support swap()
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
temp.normalize();
temp.swap(w);
}
}
```text
**Key differences:**
- Classes have **explicit interfaces** based on function signatures
- Templates have **implicit interfaces** based on valid expressions
- Classes have **runtime polymorphism** via virtual functions
- Templates have **compile-time polymorphism** via template instantiation
### Item 42: Understand the Two Meanings of typename
**Principle:** Use `class` and `typename` interchangeably for template parameters, but use `typename` to identify nested dependent type names.
**For template parameters - same meaning:**
```cpp
template<class T> class Widget; // Uses class
template<typename T> class Widget; // Uses typename - equivalent
```text
**For nested dependent names - must use typename:**
```cpp
template<typename C>
void print2nd(const C& container) {
if (container.size() >= 2) {
C::const_iterator iter(container.begin()); // ERROR! Is const_iterator a type?
// Compiler doesn't know if C::const_iterator is a type or a static member
}
}
// CORRECT - tell compiler it's a type
template<typename C>
void print2nd(const C& container) {
if (container.size() >= 2) {
typename C::const_iterator iter(container.begin()); // OK!
++iter;
int value = *iter;
std::cout << value;
}
}
```text
**Exception - don't use typename:**
```cpp
template<typename T>
class Derived: public Base<T>::Nested { // NOT: typename Base<T>::Nested
public:
explicit Derived(int x)
: Base<T>::Nested(x) // NOT: typename Base<T>::Nested
{
typename Base<T>::Nested temp; // But DO use typename here!
...
}
};
```text
**Typedef convenience:**
```cpp
template<typename IterT>
void workWithIterator(IterT iter) {
typedef typename std::iterator_traits<IterT>::value_type value_type; // Convenient typedef
value_type temp(*iter); // Now easier to use
...
}
```text
### Item 43: Know How to Access Names in Templatized Base Classes
**Problem:** Compilers won't look in templatized base classes for names.
```cpp
class CompanyA {
public:
void sendCleartext(const std::string& msg);
void sendEncrypted(const std::string& msg);
};
class CompanyB {
public:
void sendCleartext(const std::string& msg);
void sendEncrypted(const std::string& msg);
};
class MsgInfo { ... };
template<typename Company>
class MsgSender {
public:
void sendClear(const MsgInfo& info) {
std::string msg;
// Create msg from info
Company c;
c.sendCleartext(msg);
}
void sendSecret(const MsgInfo& info) { ... }
};
// Problem: Derived class can't find base class names
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
// Log before sending
sendClear(info); // ERROR! sendClear not found!
// Log after sending
}
};
```text
**Solutions:**
**1. this-> prefix:**
```cpp
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
this->sendClear(info); // OK! Assumes sendClear will be inherited
}
};
```text
**2. using declaration:**
```cpp
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
using MsgSender<Company>::sendClear; // Tell compiler to assume it's in base
void sendClearMsg(const MsgInfo& info) {
sendClear(info); // OK!
}
};
```text
**3. Explicit qualification:**
```cpp
template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
void sendClearMsg(const MsgInfo& info) {
MsgSender<Company>::sendClear(info); // OK but disables virtual binding
}
};
```text
### Item 44: Factor Parameter-Independent Code Out of Templates
**Principle:** Avoid template bloat by factoring out non-dependent code.
```cpp
// BAD - n separate functions generated
template<typename T, std::size_t n>
class SquareMatrix {
public:
void invert(); // Inverts matrix in place
};
SquareMatrix<double, 5> sm1;
sm1.invert(); // Instantiates SquareMatrix<double, 5>::invert
SquareMatrix<double, 10> sm2;
sm2.invert(); // Instantiates SquareMatrix<double, 10>::invert
// Two identical copies of invert() except for constant 5 vs. 10!
// BETTER - factor out size-independent code
template<typename T>
class SquareMatrixBase {
protected:
SquareMatrixBase(std::size_t n, T* pMem)
: size(n), pData(pMem) {}
void setDataPtr(T* ptr) { pData = ptr; }
void invert(std::size_t matrixSize); // Size-independent invert
private:
std::size_t size;
T* pData;
};
template<typename T, std::size_t n>
class SquareMatrix: private SquareMatrixBase<T> {
public:
SquareMatrix()
: SquareMatrixBase<T>(n, data) {}
void invert() { this->invert(n); } // Calls base class version
private:
T data[n*n];
};
```text
### Item 45: Use Member Function Templates to Accept "All Compatible Types"
**Principle:** Use member templates for generalized copying.
```cpp
template<typename T>
class SmartPtr {
public:
explicit SmartPtr(T* realPtr); // Constructor from raw pointer
// Member template for "generalized copy constructor"
template<typename U>
SmartPtr(const SmartPtr<U>& other)
: heldPtr(other.get()) { } // Initialize from compatible SmartPtr
T* get() const { return heldPtr; }
private:
T* heldPtr;
};
// Usage
class Top { ... };
class Middle: public Top { ... };
class Bottom: public Middle { ... };
SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle); // OK - Middle* converts to Top*
SmartPtr<Top> pt2 = SmartPtr<Bottom>(new Bottom); // OK - Bottom* converts to Top*
SmartPtr<const Top> pct2 = pt1; // OK - non-const to const
```text
**Note:** Member templates don't replace compiler-generated functions:
```cpp
template<typename T>
class SmartPtr {
public:
SmartPtr(const SmartPtr& other); // Copy constructor (generated by compiler)
template<typename U>
SmartPtr(const SmartPtr<U>& other); // Generalized copy constructor (member template)
};
```text
### Item 46: Define Non-member Functions Inside Templates When Type Conversions Are Desired
**Principle:** For template classes, declare non-member functions inside the class template to enable implicit type conversions.
```cpp
template<typename T>
class Rational {
public:
Rational(const T& numerator = 0, const T& denominator = 1);
const T numerator() const;
const T denominator() const;
// Friend function defined inside class template
friend const Rational operator*(const Rational& lhs, const Rational& rhs) {
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
};
// Usage
Rational<int> oneHalf(1, 2);
Rational<int> result = oneHalf * 2; // OK! 2 converts to Rational<int>
result = 2 * oneHalf; // OK! Friend function enables this
```text
### Item 47: Use Traits Classes for Information About Types
**Principle:** Traits provide compile-time information about types.
```cpp
// Standard library iterator traits
template<typename IterT>
struct iterator_traits {
typedef typename IterT::iterator_category iterator_category;
};
// Partial specialization for pointers
template<typename T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag iterator_category;
};
// Usage - different algorithm for different iterator types
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
doAdvance(iter, d, typename std::iterator_traits<IterT>::iterator_category());
}
// Random access version - O(1)
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::random_access_iterator_tag) {
iter += d;
}
// Bidirectional version - O(n)
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag) {
if (d >= 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
// Input iterator version - O(n)
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, std::input_iterator_tag) {
if (d < 0) {
throw std::out_of_range("Negative distance");
}
while (d--) ++iter;
}
```text
### Item 48: Be Aware of Template Metaprogramming
**Principle:** Template metaprogramming moves work from runtime to compile time.
```cpp
// Factorial at compile time
template<unsigned n>
struct Factorial {
enum { value = n * Factorial<n-1>::value };
};
template<>
struct Factorial<0> {
enum { value = 1 };
};
int main() {
std::cout << Factorial<5>::value; // Prints 120, computed at compile time!
std::cout << Factorial<10>::value; // Prints 3628800, computed at compile time!
}
```text
**Benefits:**
- Makes some computations easier to express
- Shifts work from runtime to compile time
- Enables early error detection
- Can lead to smaller executables and faster code
**Drawbacks:**
- Complex syntax
- Long compile times
- Difficult to debug
## Chapter 8: Customizing new and delete
### Item 49: Understand the Behavior of the New-Handler
**Principle:** `set_new_handler` allows you to specify a function to call when memory allocation fails.
```cpp
namespace std {
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
// Custom new-handler
void outOfMem() {
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main() {
std::set_new_handler(outOfMem);
int* pBigDataArray = new int[100000000L]; // If fails, calls outOfMem
}
```text
**New-handler function should do one of:**
1. **Make more memory available** - e.g., release reserved memory
2. **Install a different new-handler** - if current one can't make more memory available
3. **Deinstall the new-handler** - pass null to `set_new_handler`
4. **Throw an exception** - of type `bad_alloc` or derived
5. **Not return** - typically by calling `abort` or `exit`
**Per-class new-handlers:**
```cpp
class Widget {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
std::new_handler Widget::currentHandler = 0;
std::new_handler Widget::set_new_handler(std::new_handler p) throw() {
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {
NewHandlerHolder h(std::set_new_handler(currentHandler)); // Install Widget's handler
return ::operator new(size); // Allocate or throw
// h's destructor restores global handler
}
```text
### Item 50: Understand When It Makes Sense to Replace new and delete
**Reasons to replace:**
**1. Detect usage errors:**
```cpp
static const int signature = 0xDEADBEEF;
typedef unsigned char Byte;
void* operator new(std::size_t size) throw(std::bad_alloc) {
size_t realSize = size + 2 * sizeof(int);
void* pMem = malloc(realSize);
if (!pMem) throw std::bad_alloc();
// Write signature at front and back
*(static_cast<int*>(pMem)) = signature;
*(reinterpret_cast<int*>(static_cast<Byte*>(pMem) + realSize - sizeof(int))) = signature;
return static_cast<Byte*>(pMem) + sizeof(int);
}
void operator delete(void* pMemory) throw() {
// Check signatures, report corruption if found
}
```text
**2. Improve efficiency:**
- Custom allocators can be faster for specific usage patterns
- Reduce overhead of general-purpose allocators
- Pool allocators for fixed-size objects
**3. Collect usage statistics:**
- Track allocation sizes, lifetimes, patterns
- Identify memory leaks
- Optimize allocation strategy
**4. Increase speed:**
- Object pools
- Arena allocators
- Stack-based allocators
**5. Reduce memory overhead:**
- Custom allocators can have less overhead than default
**6. Accommodate special platforms:**
- Shared memory, memory-mapped files, etc.
### Item 51: Adhere to Convention When Writing new and delete
**Conventions for operator new:**
```cpp
void* operator new(std::size_t size) throw(std::bad_alloc) {
using namespace std;
if (size == 0) {
size = 1; // Handle 0-byte requests
}
while (true) {
// Attempt allocation
void* p = malloc(size);
if (p) {
return p; // Success
}
// Allocation failed; find current new-handler
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if (globalHandler) {
(*globalHandler)(); // Call it
} else {
throw bad_alloc(); // No handler, throw
}
}
}
```text
**Class-specific operator new must handle requests for wrong size:**
```cpp
class Base {
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
};
class Derived: public Base { ... };
void* Base::operator new(std::size_t size) throw(std::bad_alloc) {
if (size != sizeof(Base)) { // Wrong size!
return ::operator new(size); // Let standard operator new handle it
}
// Handle size == sizeof(Base) case
}
```text
**Conventions for operator delete:**
```cpp
void operator delete(void* rawMemory) throw() {
if (rawMemory == 0) return; // Do nothing if null pointer
// Deallocate memory
free(rawMemory);
}
// Class-specific version
class Base {
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
static void operator delete(void* rawMemory, std::size_t size) throw();
};
void Base::operator delete(void* rawMemory, std::size_t size) throw() {
if (rawMemory == 0) return;
if (size != sizeof(Base)) { // Wrong size - derived object!
::operator delete(rawMemory); // Let standard handle it
return;
}
// Deallocate memory for Base-sized object
return;
}
```text
### Item 52: Write Placement delete If You Write Placement new
**Principle:** If you write placement new, write corresponding placement delete.
```cpp
class Widget {
public:
// Normal new
static void* operator new(std::size_t size) throw(std::bad_alloc);
// Placement new (takes ostream)
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
// Normal delete
static void operator delete(void* pMemory) throw();
// Placement delete (matches placement new)
static void operator delete(void* pMemory, std::ostream& logStream) throw();
};
// If Widget constructor throws after placement new...
Widget* pw = new (std::cerr) Widget; // Calls placement new
// If constructor throws, placement delete called automatically
```text
**Problem - name hiding:**
```cpp
class Base {
public:
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
};
class Derived: public Base {
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
};
Derived* p = new (std::clog) Derived; // ERROR! Base's placement new is hidden!
```text
**Solution:**
```cpp
class StandardNewDeleteForms {
public:
// Normal new/delete
static void* operator new(std::size_t size) throw(std::bad_alloc) {
return ::operator new(size);
}
static void operator delete(void* pMemory) throw() {
::operator delete(pMemory);
}
// Placement new/delete
static void* operator new(std::size_t size, void* ptr) throw() {
return ::operator new(size, ptr);
}
static void operator delete(void* pMemory, void* ptr) throw() {
return ::operator delete(pMemory, ptr);
}
// Nothrow new/delete
static void* operator new(std::size_t size, const std::nothrow_t& nt) throw() {
return ::operator new(size, nt);
}
static void operator delete(void* pMemory, const std::nothrow_t&) throw() {
::operator delete(pMemory);
}
};
class Widget: public StandardNewDeleteForms {
public:
using StandardNewDeleteForms::operator new; // Make standard forms visible
using StandardNewDeleteForms::operator delete;
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
static void operator delete(void* pMemory, std::ostream& logStream) throw();
};
```text
## Chapter 9: Miscellany
### Item 53: Pay Attention to Compiler Warnings
**Principle:** Take compiler warnings seriously and strive for warning-free code.
```cpp
class B {
public:
virtual void f() const;
};
class D: public B {
public:
virtual void f(); // Forgot const
};
// Compiler warning:
// "D::f() hides virtual B::f()"
// This is BAD! D::f doesn't override B::f, it hides it!
```text
**Best practices:**
- Treat warnings as errors (compiler flags like `-Werror`)
- Understand what each warning means
- Fix warnings, don't suppress them without good reason
- Different compilers have different warnings - test with multiple compilers
- Warning-free code at max warning level shows code quality
### Item 54: Familiarize Yourself with the Standard Library
**Standard C++ Library includes:**
**From C:**
- `<cstddef>`, `<cstdlib>`, `<cstring>`, etc.
**iostreams:**
- `<iostream>`, `<fstream>`, `<sstream>`, `<iomanip>`
- Better type safety than C's printf/scanf
**Containers:**
- `<vector>`, `<list>`, `<deque>`, `<set>`, `<map>`, `<stack>`, `<queue>`
- `<array>`, `<forward_list>`, `<unordered_set>`, `<unordered_map>` (C++11)
**Algorithms:**
- `<algorithm>`, `<numeric>`
- `find`, `sort`, `transform`, `accumulate`, etc.
**Iterators:**
- Pointer-like objects for containers
- Input, output, forward, bidirectional, random access
**Function Objects:**
- `<functional>`
- Objects that act like functions
**Smart Pointers (C++11):**
- `<memory>`
- `unique_ptr`, `shared_ptr`, `weak_ptr`
**Strings:**
- `<string>`
- Better than char arrays
**Regular Expressions (C++11):**
- `<regex>`
**Random Numbers (C++11):**
- `<random>`
- Better than C's rand()
**Threading (C++11):**
- `<thread>`, `<mutex>`, `<condition_variable>`, `<atomic>`, `<future>`
**Time (C++11):**
- `<chrono>`
**Tuples (C++11):**
- `<tuple>`
### Item 55: Familiarize Yourself with Boost
**Boost libraries provide:**
**String and text processing:**
- Boost.Regex (regular expressions)
- Boost.Spirit (parser framework)
- Boost.StringAlgo
**Containers:**
- Boost.Array (fixed-size arrays)
- Boost.MultiIndex (multiple indexed views)
- Boost.Bimap (bidirectional maps)
**Function objects and higher-order programming:**
- Boost.Bind (function binding)
- Boost.Lambda (lambda expressions - predates C++11)
- Boost.Function (function wrappers - now in std::function)
**Generic programming:**
- Boost.ConceptCheck (concept checking)
- Boost.TypeTraits (type traits - many now in std)
**Template metaprogramming:**
- Boost.MPL (metaprogramming library)
- Boost.Fusion (compile-time and runtime algorithms)
**Math and numerics:**
- Boost.Math (math functions)
- Boost.Random (random number generators - many now in std)
**Correctness and testing:**
- Boost.Test (unit testing framework)
- Boost.StaticAssert (compile-time assertions)
**Data structures:**
- Boost.Variant (discriminated union)
- Boost.Optional (optional values)
- Boost.Any (typesafe container for single values)
**Inter-language support:**
- Boost.Python (Python/C++ interoperability)
**Memory:**
- Boost.SmartPtr (smart pointers - many now in std)
- Boost.PointerContainer (containers for pointers)
**Miscellaneous:**
- Boost.DateTime (date and time handling)
- Boost.Filesystem (filesystem paths and operations - now in std)
- Boost.Thread (threading - many features now in std)
- Boost.Asio (asynchronous I/O)
**Why use Boost:**
- Peer-reviewed code
- Production-quality
- Cross-platform
- Many Boost libraries become C++ Standard Library components
- Actively maintained and improved