Path: utzoo!attcan!uunet!cs.utexas.edu!rutgers!uwvax!sevenlayer.cs.wisc.edu!bothner From: bothner@sevenlayer.cs.wisc.edu (Per Bothner) Newsgroups: comp.lang.c++ Subject: A Parameterized Class for Semi-automatic Memory Management Message-ID: <11329@spool.cs.wisc.edu> Date: 23 Sep 90 01:44:57 GMT Sender: news@spool.cs.wisc.edu Organization: U of Wisconsin CS Dept Lines: 119 Many applications manage memory using a convention that certain references are the only existing ones to the referents. That is, no other pointer can legally reference that object. We can say that the (implicit) "reference count" of the object is one. Let us say that such a reference (pointer) is 'owned'. We also say that the owned reference points to an owned object. Non-automatic storage management depends on keeping track of which pointers are owned. Examples: * If a function returns an owned pointer/reference, the caller is reponsible for deleting the returned object. * If a class field is owned, the object it points to should be deleted by the class's destructor. * If a formal parameter is owned, the called function must delete it before returning. Alternatively, it can "give" away ownership. It is easily to lose track of which pointers are owned and which are not. The following idea makes it easy to keep track of this, and can to some extent automate the job. (The idea is inspired by an idea of Charles Haynes, of Digital Equipment Corporation's Western Software Laboratory.) THE SOLUTION We define a new standard parameterized class: template class owned { private: T* object; public: owned(T* ptr) { object = ptr; } // Normal contructor owned(owned& X) { object = X.object; X.clear(); } // Steal ownership clear() { object = NULL; } // Remove ownership (and reference) T* operator->() { return object; } // Get actual pointer ~owned() { delete object; } // Desctructor deletes object }; The clear() method can be used when automatic deletion of object is to be inhibited, perhaps because the object has been "given" to some other owner. EXAMPLES OF USE * A function that returns an owned object: owned F(...) { owned myfoo(new Foo(...)); return myfoo; } * Passing an owned object as a parameter: void G(owned myfoo) { myfoo->do_something(); // object is automatically deleted on exit. } void H() { owned myfoo = ...; G(myfoo); // gives ownership away to G // At this point myfoo is invalid. // Its pointer is NULL, so the (old) owned object won't be deleted twice } * An owned field: struct Bar { public: owned myfoo; Bar(...) : myfoo(new Foo(...)) { ...} print() { ... myfoo->print(); ... } }; Note that Bar::myfoo is automatically deleted when a Bar object is destroyed. Bar::print shows how the (Foo) object can be accessed without giving away ownership. * Re-using an owned parameter: owned operator+(owned x, owned y) { x += y; return x; // The y object gets deleted, but the x object is re-used for the sum } REFERENCES INSTEAD OF POINTERS Since an owned "owns" the object itself, not just a pointer to it, it would be preferable sense to think of an owned as an encapsulated T&, rather than an encapsulated T*. Such a definition would look like the following, except it would not be allowed, since C++ currently lacks 'operator.'. (There seems to be some sentiment for adding operator. to the language definitions; consider this note as support for these efforts.) template class owned { private: T* object; public: // Copy constructor steals object. clear() { object = NULL; } owned(owned& X) { object = X.object; X.clear(); } owned(T& ref) { object = &ref; } T& operator.() { return *T; } // NOT ALLOWED BY CURRENT C++ ~owned() { delete object; } }; -- --Per Bothner bothner@cs.wisc.edu Computer Sciences Dept, U. of Wisconsin-Madison