100 likes | 215 Vues
This document discusses the critical aspects of managing polymorphism in C++ using pointers and references, focusing on object ownership, efficiency, and memory management. It highlights the importance of reference counting to ensure safe deletion of objects contained within STL containers, as well as provides solutions to common problems encountered in object-oriented programming. The text also introduces the Counted Pointer Idiom for effective memory management and explores copy-on-write semantics for mutable objects. Practical examples illustrate how to implement these concepts.
E N D
Reference counting, handles and the STL Fred Kuhns fredk@cse.wustl.edu Applied Research Laboratory, Department of Computer Science and Engineering, Washington University in St. Louis
Background • In order to take advantage of polymorphism in C++ you must use either pointers or references. • The question of object ownership is critical • Containers own the objects they contain: • copy is made on insertion • object deleted when removed or container deleted • Often you will use Object pointers with STL containers • Consequences: • could make a new object each time it is referenced • make one object, then copy its pointer CSE332: Object Oriented Programming Laboratory
Issues • Object use issues: • is this a const object (all users need read-only access). Then multiple copes or one copy and multiple references is fine • if users alter object then what are the semantics? Should each user have their own copy or is one global object required. • if object is not changed frequently then copy-on-write semantics is viable • efficiency issues: • many copies of an object • creates time and space overhead • how to keep all copies consistent (or knowing if you need to) • One copy with many references: • concurrency control issues • knowing when an object is no longer needed CSE332: Object Oriented Programming Laboratory
Problems and Solutions • context: class hierarchy captures behavioral differences • problem: container is only able to store objects of a specific type • solution: store object references or addresses in containers • context: containers own contained objects • problem: objects are copied causing efficiency problems • solution: store object pointers in containers • context: object pointer appears in many containers. • problem: how do you know when it is safe to delete object • solution: reference counting • context: many references to an object that is infrequently changed. • problem: changes should only be visible to user making the change. • solution: copy-on-write semantics CSE332: Object Oriented Programming Laboratory
A more general observation • “Counted Pointer Idiom”, J.O. Coplien, Advanced C++ - Programming Styles and Idioms • context: memory management of dynamically created objects • pointers are convenient for dynamic structures (trees etc) and for sharing • passing object pointers is efficient • problem: managing object pointers is error prone. • Solution: known by many names - Counted Pointer Idiom (aka Handler idiom); proxy pattern; smart pointers; Handle-Body idiom • Handler can be passed by value • Pointer may be assigned to Handler so when you leave the enclosing scope Handler is destroyed CSE332: Object Oriented Programming Laboratory
Reference Counting Techniques (intrusive) class Handle { public: Handle(…) { body = new Body(…); body->refCount++; } Handle(const Handle& h) { body = h.body; body->refCount++; } Handle& operator=(const Handle& h) { h.body->refCount++; if (--body->refCount <= 0) delete body; body = h.body; return *this; } ~Handle() { if (--body->refCount <= 0) delete body; } Body* operator->() {return body;} private: Body *body; }; class Body { public: void service(); private: friend class Handle; Body( … ) { … } ~Body( … ) { … } int refCount; }; CSE332: Object Oriented Programming Laboratory
Non-Intrusive Example template <class X> class Handle { X* rep; int* pcount; public: Handle() : rep(new X), pcount(new int(1)){} Handle(X* pp): rep(pp), pcount(new int(1)){} Handle(const Handle& r) : rep(r.rep), pcount(r.pcount){*pcount)++;} Handle<X>& operator=(const Handle<X>& r) { if (rep == r.rep) return *this; if(--(*pcount) == 0) { delete rep; delete pcount; } rep = r.rep; pcount = r.pcount; (*pcount)++; return *this; } ~Handle() { if (--(*pcount) == 0) {delete rep; delete pcount;} } X* operator->() {return rep;} }; Can you think of other operators for handler? CSE332: Object Oriented Programming Laboratory
Do a little more • If you need to perform some extra processing on the Body object you may replicate the representation classes interface within the Handle class. • For example, in a multithreaded program (or multi-process with shared memory) you can add locking primitives to the appropriate method calls or member object references. template <class T> class ImplHandler { T* rep; Lock lock; int *pcount; public: void value() {Lock_ptr x(lock); return rep->value();} … }; CSE332: Object Oriented Programming Laboratory
Copy-On-Write Semantics • Use a Handle to reference object • if const object returned then OK • if not const then need to know if user is/will write to the object • overload any and all body member functions that alter the object’s state. operator=() and operator*() are likely candidates CSE332: Object Oriented Programming Laboratory
String Class Example • class String { • private: • class StrRep { • // define how string is stored and managed • … }; • StrRep* *srep_; • public: • class Cref { • friend class String; String& s_; int i_; • Cref(String &s, int i) : s_(s), i_(i) {} • public: • operator char() {return s_.read(i_);} // type conversion • void operator=(char c) {s_.write(i_, c);} // assignment • }; • String& operator=(const String& s) { • s.srep_->ref_++; • if (--srep_->ref_ == 0) delete srep_; • srep_ = s.srep_; return *this; • } • char read(int i) const {return srep_->str_[i];} • void write(int i, char c) • {srep_ = srep_->get_copy(); srep_->str_[i] = c;} • char operator[](int i) const {return srep_->str_[i];} • Cref operator[](int i) {return Cref(*this, 0);} • … }; CSE332: Object Oriented Programming Laboratory