Policy-Based Design
Programming
This program demonstrates policy-based design, an advanced C++ design pattern that uses templates to compose behavior through policies. This example creates a smart pointer with configurable ownership and threading policies.
Implementation
#include <iostream>
#include <atomic>
#include <memory>
// Policy: Reference counting for shared ownership
struct RefCounted {
template <typename T>
class OwnershipPolicy {
private:
T* ptr_;
std::atomic<int>* refCount_;
public:
OwnershipPolicy(T* ptr) : ptr_(ptr), refCount_(new std::atomic<int>(1)) {}
OwnershipPolicy(const OwnershipPolicy& other) : ptr_(other.ptr_), refCount_(other.refCount_) {
++(*refCount_);
}
OwnershipPolicy& operator=(const OwnershipPolicy& other) {
if (this != &other) {
release();
ptr_ = other.ptr_;
refCount_ = other.refCount_;
++(*refCount_);
}
return *this;
}
~OwnershipPolicy() { release(); }
T* get() const { return ptr_; }
void release() {
if (refCount_ && --(*refCount_) == 0) {
delete ptr_;
delete refCount_;
}
}
};
};
// Policy: No-op (no special thread safety)
struct NoThreading {
struct ThreadingPolicy {
void lock() {}
void unlock() {}
};
};
// Combine Policies into a SmartPointer
template <typename T,
template <typename> class OwnershipPolicy = RefCounted::OwnershipPolicy,
typename ThreadingPolicy = NoThreading::ThreadingPolicy>
class SmartPointer : private OwnershipPolicy<T>, private ThreadingPolicy {
public:
explicit SmartPointer(T* ptr) : OwnershipPolicy<T>(ptr) {}
T* operator->() {
lock();
return OwnershipPolicy<T>::get();
}
T& operator*() {
lock();
return *(OwnershipPolicy<T>::get());
}
~SmartPointer() { unlock(); }
private:
void lock() { ThreadingPolicy::lock(); }
void unlock() { ThreadingPolicy::unlock(); }
};
// Example usage
struct Test {
void sayHello() const { std::cout << "Hello, World!" << std::endl; }
};
int main() {
// Create a smart pointer with ref-counting and no threading
SmartPointer<Test> ptr(new Test);
ptr->sayHello();
// Copy demonstrates shared ownership
SmartPointer<Test> ptr2 = ptr;
ptr2->sayHello();
return 0;
} Key Concepts
- Policy-Based Design: Composes behavior through template parameters
- Ownership Policy: Defines how resources are managed (reference counting in this example)
- Threading Policy: Defines thread-safety behavior (no-op in this example)
- Template Template Parameters: Allows passing template classes as parameters
- Policies can be mixed and matched to create flexible, reusable components
Benefits
- Flexibility: Mix and match policies at compile time
- Zero overhead: No runtime cost for unused policies
- Type safety: Compile-time composition