More C++ Idioms/Counted Body

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

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

[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)