home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!elroy.jpl.nasa.gov!sdd.hp.com!cs.utexas.edu!tamsun.tamu.edu!snorkelwacker.mit.edu!ai-lab!life.ai.mit.edu!tmb
- From: tmb@arolla.idiap.ch (Thomas M. Breuel)
- Newsgroups: comp.lang.c++
- Subject: Re: Reference counting for vectors, (Tony Hansen's book).
- Message-ID: <TMB.92Aug16160535@arolla.idiap.ch>
- Date: 16 Aug 92 20:05:35 GMT
- References: <1992Aug14.164719.9719@wuecl.wustl.edu>
- <BRISTER.92Aug14110706@tirade.decwrl.dec.com>
- <TMB.92Aug14232208@arolla.idiap.ch>
- <BRISTER.92Aug14170213@tirade.decwrl.dec.com>
- Sender: news@ai.mit.edu
- Reply-To: tmb@idiap.ch
- Organization: IDIAP (Institut Dalle Molle d'Intelligence Artificielle
- Perceptive)
- Lines: 165
- In-reply-to: brister@decwrl.dec.com's message of 15 Aug 92 00:02:13 GMT
-
- In article <BRISTER.92Aug14170213@tirade.decwrl.dec.com> brister@decwrl.dec.com (James Brister) writes:
-
- On 15 Aug 92 03:22:08 GMT, tmb@arolla.idiap.ch (Thomas M. Breuel) said:
- > Using reference counting to get reference semantics on parameter
- > passing is very confusing indeed (sadly, this bad idea seems to
- > pervade the C++ literature).
-
- Perhaps if it's so pervasive then it's not such a bad idea.
-
- parameter passing was only a simple example, there are lots of cases where
- multiple objects need to keep track of a piece of data, and unless you're
- very sure about who is supposed to delete the data and when (non-trivial
- when the system gets complex), you can get yourself into a lot of trouble.
- Reference counting can save the day.
-
- Memory management and reference/value semantics are very different
- concepts (though implementationally closely related).
-
- From the user's point of view, there is no difference in terms of
- memory management between (correctly implemented) arrays with
- reference semantics or arrays with value semantics. You don't have to
- think about "who is supposed to delete the data" in either case.
-
- In terms of behavior, there is, of course, a big difference. Arrays
- with reference semantics mean that any name that has been initialized
- from, or assigned to, from some other such array object will be
- aliased to the same piece of memory. Unexpected aliasing teds to lead
- to difficult to trace bugs in programs.
-
- Arrays with value semantics, on the other hand, behave just like
- scalars and structures, which is what programmers expect and are used
- to. The worst that can happen is that you incur a few redundant
- copies, and if those happen to make a difference in terms of
- performance (which is _very_ rare), you can find those places by
- profiling.
-
- Personally, I would prefer to be able to disallow assignment
- ("operator=(A&)") and copy constructor ("A(A&)") for my array classes
- altogether. Copying is a potentially expensive operation, and hence
- the user should ask for it explicitly. Aliasing (as you get it with
- reference counting implementations of arrays) is a dangerous
- operation, and hence the user should also ask for it explicitly.
-
- Unfortunately, C++ forces you to use the same function (the copy
- constructor) for passing parameters, returning values, and
- initialization of variables. I have always considered this a
- shortcoming, although I'm not sure that it is fixable.
-
- You can get a simple template implementation of arrays with value
- semantics via anonymous FTP from maya.idiap.ch:pub/tmb/array.shar.
-
- > If you truly want reference counting semantics, you can easily derive
- > it from objects with value semantics using a template class.
-
- See below for an implementation. I wrote it mostly for fun. I find
- reference counted semantics pretty useless, so I haven't tested it
- much.
-
- > Copy-on-write is not really an option for classes like arrays that
- > require high-performance updates. You don't want to pay the price for
- > the memory fetch and conditional branch on each array store.
-
- If the array copies itself the first time it is written to, then you don't
- loose anything except on the first access, and with large data it would be
- better to have COW than to duplicate everything to protect against
- unintended changes.
-
- This is not true. In general, you have to check a flag on every (not
- just the first) modification to see whether the array has been copied.
-
- As usual, you can take my advice or leave it. I have found arrays with
- reference semantics to be a bother, and I recommend that people stay
- away from them.
-
- Whether you use copy-on-write to get value semantics or something else
- makes little difference, except that copy-on-write has _some_ overhead
- on every update. For numerical code, I have found that a "dumb"
- implementation of arrays with value semantics is the better choice.
-
- Thomas.
-
- ================================================================
-
- Counted.h
-
- #ifndef __COUNTED__
- #define __COUNTED__
-
- template <class T>
- struct Counted {
- private:
- int *count;
- T *object;
- void drop() {
- if(!count) return;
- (*count)--;
- if(*count<=0) {
- delete count;
- delete object;
- count=0;
- object=0;
- }
- }
- void acquire() {
- (*count)++;
- }
- public:
- Counted() {
- count=0;
- object=0;
- }
- Counted(T *object):object(object) {
- count = new int(1);
- }
- ~Counted() {
- drop();
- }
- Counted(Counted &other) {
- count=other.count;
- object=other.object;
- acquire();
- }
- Counted &operator=(Counted &other) {
- drop();
- count=other.count;
- object=other.object;
- acquire();
- return *this;
- }
-
- T &operator*() {return *object;}
- T *operator->() {return object;}
- operator T() {return *object;}
-
-
- // do _not_ provide "operator T*()"
- };
-
- #endif
-
- ================================================================
-
- A simple test program for the above:
-
- extern "C" {
- #include <stdio.h>
- }
- #include "Counted.h"
-
- struct A {
- int val;
- A() { printf("created A@%p\n",this); }
- ~A() { printf("destroyed A@%p\n",this); }
- };
-
- main() {
- Counted<A> x(new A);
- x->val = 42;
- printf("x@%p\n",&(*x));
- Counted<A> y(x);
- Counted<A> z;
- z=x;
- printf("z@%p\n",&(*z));
- printf("%d\n",z->val);
- }
-