More C++ Idioms/Counted Body
From Wikibooks, the open-content textbooks collection
Contents |
[edit]
Counted Body/Reference Counting (intrusive)
[edit] Intent
Manage logical sharing of a resource/object, prevent expensive copying, and allow proper resource deallocation of objects that use dynamically allocated resources.
[edit] Also Known As
- Reference Counting (intrusive)
- Counted Body
[edit] Motivation
When Handle/Body idiom is used, quite often it is noticed that copying of bodies is expensive. This is because copying of bodies involves allocation of memory and copy construction. Copying can be avoided by using pointers and references, but these leave the problem of who is responsible for cleaning up the object. Some handle must be responsible for releasing memory resources allocated for the body. Usually it is the last one. Without automatic reclamation of memory resources of memory, it leaves a user-visible distinction between built-in types and user-defined types.
[edit] Solution and Sample Code
The solution is to add a reference count to the body class to facilitate memory management; hence the name "Counted Body." Memory management is added to the handle class, particularly to its implementation of initialization, assignment, copying, and destruction.
namespace { // anonymous namespace class StringRep { friend class String; StringRep(const char *s): count(1) { strcpy(rep=new char[strlen(s)+1], s); } ~StringRep() { delete [] rep; } int count; char *rep; }; } // anonymous namespace class String { public: String():rep(new StringRep("")) { } String(const String &s): rep(s.rep) { rep->count++; } String &operator=(const String &s){ String(s).swap(*this); // copy-and-swap idiom return *this; } ~String() { // StringRep deleted only when the last handle goes out of scope. if(rep && --rep->count <= 0) delete rep; } String(const char *s): rep(new StringRep(s)) { } void swap (String & s) throw () { std::swap(this->rep, s.rep); } . . . . private: StringRep *rep; }; int main() { String a = "hello", b = "world"; a = b; return 0; }
Gratuitous copying is avoided, leading to a more efficient implementation. This idiom presumes that the programmer can edit the source code for the body. When that's not possible, use Detached Counted Body. When counter is stored inside body class, it is called intrusive reference counting and when the counter is stored external to the body class it is known as non-intrusive reference counting. This implementation is a variation of shallow copy with the semantics of deep copy and the efficiency of Smalltalk name-value pairs.
[edit] Consequences
Creation of multiple reference counts will result into multiple deletion of the same body, which is undefined. Care must be taken to avoid creating multiple reference counts to the same body. Intrusive reference counting easily supports it. With non-intrusive reference counting, programmer discipline is required to prevent duplicate reference counts.
[edit] Known Uses
- boost::shared_ptr (non-intrusive reference counting)
- boost::intrusive_ptr (intrusive reference counting)
- std::tr1::shared_ptr
- the Qt toolkit, e.g. QString
[edit] Related Idioms
- Handle Body
- Detached Counted Body (non-intrusive reference counting)
- Smart Pointer
- Copy-and-swap
[edit] References
http://users.rcn.com/jcoplien/Patterns/C++Idioms/EuroPLoP98.html#CountedBody
[edit] Copyright
Copyright ©1998 Lucent Technologies, Bell Labs Innovations. All rights reserved. Permission granted to reprint verbatim for non-commercial use provided this copyright notice appears. (Contents modified and enhanced for Wikibooks)