//============================================================================ // Contents: // // Definition of countable_ptr template class and its member functions. // countable_ptr implements a reference counted smart pointer for pointers to // types that satisfy countable requirements (defined below). // // The code demonstrates a generalised implemention of the Counted Body idiom // (aka Attached Counted Handle/Body idiom). The benefit of an approach based // on generic programming is that the requirements for counting are separated // from the implementation mechanism for counting. This open approach means // that countable_ptr is suitable for a wide variety of different // implementations, and may adapt to existing ones, rather than requiring a // new smart pointer type for each strategy. // // The code is in many ways a traditional implementation of the Counted Body // idiom in that it is intrusive, ie countability is acquired explicitly and // statically by derivation for a given class. This means that the reference // count is explicitly a part of objects even if it is unused (eg in the case // of composite members or auto variables), and that only classes over which // you have control can use it. However, by satisfying the countability // requirements for countable_ptr no new smart pointer class is required to // use classes derived from countability. // // History: // // Initial version created by Kevlin Henney, kevlin@acm.org, January 1998. // // Permissions: // // Copyright Kevlin Henney, 1998. All rights reserved. // // Permission to use, copy, modify, and distribute this software for any // purpose is hereby granted without fee, provided that this copyright and // permissions notice appear in all copies and derivatives, and that no // charge may be made for the software and its documentation except to cover // cost of distribution. // // This software is provided "as is" without express or implied warranty. // // Notes: // // As there is no requirement that a countable type must be a class, typename // is used to introduce type parameters rather than class. If your compiler // does not yet support this use of typename, you can replace it with class. // // For practical reasons the global, rather than a named namespace, has been // used to hold the contents of this header. In future the use of a separate // namespace is preferred and recommended. // // This code has been written to conform to standard C++ (in final draft // status at the time of writing). It has been compiled successfully using // the operational subset of standard features implemented by Microsoft // Visual C++ 5.0. //============================================================================ #ifndef COUNTABLE_PTR_INCLUDED #define COUNTABLE_PTR_INCLUDED //---------------------------------------------------------------------------- // Description: // // Definition of countable_ptr template class, which implements a reference // counted smart pointer template for types that satisfy countable // requirements. The class is a concrete class not intended as a base class. // // Requirements: // // For a type to be countable it must satisfy the following requirements, // where ptr is a non-null pointer to a single object (ie not an array) of // the type, and #function indicates number of calls to function(ptr): // // +===================+=====================+=============================+ // | expression | return type | semantics and notes | // +===================+=====================+=============================+ // | aquire(ptr) | no requirement | post: acquired(ptr) | // +-------------------+---------------------+-----------------------------+ // | release(ptr) | no requirement | pre: acquired(ptr) | // | | | post: acquired(ptr) == | // | | | #acquire > #release | // +-------------------+---------------------+-----------------------------+ // | acquired(ptr) | convertible to bool | return: #acquire > #release | // +-------------------+---------------------+-----------------------------+ // | dispose(ptr, ptr) | no requirement | pre: !acquired(ptr) | // | | | post: *ptr no longer usable | // +===================+=====================+=============================+ // // Note that the two arguments to dispose are to support selection of the // appropriate type safe version of the function to be called. In the general // case the intent is that the first argument determines the type to be // deleted, and would typically be templated, while the second selects which // template to use, eg by conforming to a specific base class. // // In addition the following requirements must also be satisfied, where null // is a null pointer to the countable type: // // +=====================+=====================+=====================+ // | expression | return type | semantics and notes | // +=====================+=====================+=====================+ // | aquire(null) | no requirement | action: none | // +---------------------+---------------------+---------------------+ // | release(null) | no requirement | action: none | // +---------------------+---------------------+---------------------+ // | acquired(null) | convertible to bool | return: false | // +---------------------+---------------------+---------------------+ // | dispose(null, null) | no requirement | action: none | // +=====================+=====================+=====================+ // // Note that there are no requirements on these functions in terms of // exceptions thrown or not thrown, except that if exceptions are thrown the // functions themselves should be exception safe. // // In principle these functions may be used on an object independently of // countable_ptr, but for a number of reasons this is inadvisable and no // guarantees (except "you'll be sorry") are made for mixed use (eg using // both countable_ptr and manual calls of countable functions on an object). // // Notes: // // The constructor taking a single pointer has been made explicit to prevent // accidental conversions, but the explicit keyword can be removed if your // compiler does not support it without affecting the intent. // // For brevity, equality and Boolean operators have been omitted, but are // simple to add according to the model you wish to support. // // For brevity and portability, member templates for the copy constructor // and for the copy assignment operator have been omitted. These are simple // to implement, and are identical in behaviour to the regular copy // constructor and copy assignment operator [NB: use the get member function // to gain access to the held pointer]. // // Related member functions (method categories) are placed under their own // commented access specifiers. // // The naming convention adopted is in part based on the standard library, // ie get, clear and assign take their names and basic behaviour from the // spec for auto_ptr and basic_string. //---------------------------------------------------------------------------- template class countable_ptr { public: // construction and destruction explicit countable_ptr(countable_type *); countable_ptr(const countable_ptr &); ~countable_ptr(); public: // access countable_type *operator->() const throw(); countable_type &operator*() const throw(); countable_type *get() const throw(); public: // modification countable_ptr &clear(); countable_ptr &assign(countable_type *); countable_ptr &assign(const countable_ptr &); countable_ptr &operator=(const countable_ptr &); private: // representation countable_type *body; }; //---------------------------------------------------------------------------- // Description: // // Definition of countable_ptr template class member functions. // // Notes: // // Definitions could be placed in a separate header file or, for systems that // support separate compilation of templates, in a source file. // // A number of functions are likely candidates for explicit inlining, but for // the purposes of demonstration such an optimisation has not been deemed // necessary. //---------------------------------------------------------------------------- template countable_ptr::countable_ptr(countable_type *initial) : body(initial) { acquire(body); } template countable_ptr::countable_ptr(const countable_ptr &other) : body(other.body) { acquire(body); } template countable_ptr::~countable_ptr() { clear(); } template countable_type *countable_ptr::operator->() const throw() { return body; } template countable_type &countable_ptr::operator*() const throw() { return *body; } template countable_type *countable_ptr::get() const throw() { return body; } template countable_ptr &countable_ptr::clear() { return assign(0); } template countable_ptr & countable_ptr::assign(countable_type *rhs) { // set to rhs (note that this sequence is self assignment safe) acquire(rhs); countable_type *old_body = body; body = rhs; // tidy up release(old_body); if(!acquired(old_body)) { dispose(old_body, old_body); } return *this; } template countable_ptr & countable_ptr::assign(const countable_ptr &rhs) { return assign(rhs.body); } template countable_ptr & countable_ptr::operator=(const countable_ptr &rhs) { return assign(rhs); } #endif