/**************************************************************************** ** COPYRIGHT (C): 1997 Cay S. Horstmann. All Rights Reserved. ** PROJECT: Practical OO Development with C++ and Java ** FILE: rc_ptr.cpp ** PURPOSE: smart pointers with reference counting ** VERSION 1.0 ** PROGRAMMERS: Cay Horstmann (CSH) ** RELEASE DATE: 3-15-97 (CSH) ** UPDATE HISTORY: ****************************************************************************/ /* Project: Console Application Add files rc_ptr.cpp Additional include directory: \PracticalOOBook\cpplib To compile sample code, define preprocessor variable: RC_PTR_TEST */ #include "setup.h" #include #include EXPORT class rc_base { public: void init() { _rc = 1; } bool is_unique() const { return _rc == 1; } void incref() { ++_rc; } int decref() { return --_rc; } private: int _rc; }; EXPORT template class rc_wrapper : public rc_base, public X {}; EXPORT template class rc_ptr { public: rc_ptr() : _pwrap(NULL) {} rc_ptr(const rc_ptr& b) { copy(b); } const rc_ptr& operator=(const rc_ptr& b) { if (this != &b) { free(); copy(b); } return *this; } ~rc_ptr() { free(); } X* operator->() { assert(_pwrap != NULL); return (X*)_pwrap; } const X* operator->() const { assert(_pwrap != NULL); return (const X*)_pwrap; } X& operator*() { assert(_pwrap != NULL); return *(X*)_pwrap; } const X& operator*() const { assert(_pwrap != NULL); return *(const X*)_pwrap; } bool operator!() const { return _pwrap == NULL; } bool operator==(int n) const { return n == 0 && _pwrap == NULL; } bool operator!=(int n) const { return n != 0 || _pwrap != NULL; } bool operator==(const rc_ptr& b) const { return _pwrap == b._pwrap; } bool operator!=(const rc_ptr& b) const { return _pwrap != b._pwrap; } rc_ptr(X* p) { _pwrap = (rc_wrapper*)p; if (_pwrap) _pwrap->incref(); } operator const X*() const { return (const X*)_pwrap; } const rc_ptr& operator=(const X* p) { free(); _pwrap = (rc_wrapper*)p; if (_pwrap) _pwrap->incref(); return *this; } void free() // call to break cycles { if (_pwrap != NULL && _pwrap->decref() == 0) { ((X*)_pwrap)->~X(); delete[] (char*)_pwrap; } _pwrap = NULL; } void unique() const { if (_pwrap != NULL && !_pwrap->is_unique()) { X* px = (X*)_pwrap; new(*const_cast*>(this)) X(*px); } } rc_ptr clone() const { rc_ptr r; if (_pwrap != NULL) new(r) X(*(X*)_pwrap); return r; } private: void copy(const rc_ptr& b) { _pwrap = b._pwrap; if (_pwrap) _pwrap->incref(); } rc_wrapper* _pwrap; friend void* operator new(size_t n, rc_ptr& p); }; EXPORT template void* operator new(size_t, rc_ptr& p) { p.free(); char* cp = new char[sizeof(rc_wrapper)]; p._pwrap = (rc_wrapper*)cp; p._pwrap->init(); return (X*)p._pwrap; } #ifdef RC_PTR_TEST class A { public: A(int a = 0) : _a(a) { cout << "A constructed " << (void*)this << "\n"; } A(const A& b) : _a(b._a) { cout << "A constructed " << (void*)this << "\n"; } virtual ~A() { cout << "A destructed " << (void*)this << "\n"; } void change() { _a++; } void print() { cout << _a << endl; } private: int _a; }; class D : public A { public: D(int a = 0) : A(a) { cout << "D constructed " << (void*)this << "\n"; } D(const D& b) : A(b) { cout << "D constructed " << (void*)this << "\n"; } ~D() { cout << "D destructed " << (void*)this << "\n"; } private: }; int main() { rc_ptr pa; // initialize as null pointer if (pa == NULL) // testing operator==(int) new(pa) A(2); // construct object rc_ptr pd; if (!pd) // testing operator! new(pd) D(3); // construct object pa = pd; // conversion to base class pointer pa->print(); // testing operator-> pa->change(); // changing pa affects pd pd->print(); pa.unique(); // make unique copy pa->change(); // changing pa doesn't affect pd pd->print(); rc_ptr pe = pd.clone(); // make clone pe->change(); // changing pe doesn't affect pd pd->print(); return 0; } #endif