Topic: counted_ptr suggestion/example


Author: Igor Boukanov <Igor.Boukanov@fi.uib.no>
Date: 1996/04/22
Raw View
Subject: counted_ptr suggestion/example
Newsgroups: comp.std.c++
Organization: Fysisk institutt, Universitetet i Bergen
Summary:
Keywords: C++, auto_ptr

   Current requirement to the auto_ptr class such as ability to be returned
from functions can lead to not so cheap implementation. (Deeply discussed in
this group example has the property sizeof(auto_ptr) > sizeof(pointer)).
But by adding a little bit more overhead one can wright much more safe and
useful counted_ptr (see example below), which will always point to a
valid object, can be used with stl containers and as global variable and has
other real reference counter properties.
Of cause, you can ask me if everybody can write such classes why do I need
it to be added to C++ standard? Because in general all such classes to be
portable will have unnecessary overhead which can be avoided if such really
useful thing will be provided in any particular C++ implementation where
the code can be based on a knowledge of the compiler behavior.

------------------------- begin of code example -----------
//counted_ptr example:

template<class T> class counted_ptr {
   private:
      T* p;
      unsigned long* count;
      void release() {
         if (--(*count) == 0) {
            p->~T(); // assumption: no throw from ~T
            operator delete(count);
         }
      }
   public:
      template<class Ctor> counted_ptr(Ctor ctor) {
         // I think next line in some implementations can cause problems
         // due to incorrect alignment...
         count = static_cast<unsigned long*>
            (operator new(sizeof(unsigned long) + ctor.size()));
         // size method of Ctor should return real object size, which in
         // the case of derived classes can be > than sizeof(T)!
         try {
            p = ctor.make((void*)(count + 1));
            // Ctor::make(void*) should construct somethink and return a
            // pointer which can be assign to T*
         }
         catch(...) {
            operator delete(count);
            throw;
         }
         *count = 1;
      }
      counted_ptr(const counted_ptr<T>& r): p(r.p), count(r.count) {
         ++(*count);
      }
      ~counted_ptr() { release(); }
      counted_ptr<T>& operator=(const counted_ptr<T>& r) {
         release();
         p = r.p;
         count = r.count;
         ++(*count);
         return *this;
      }
      T* operator->() const { return p; }
      T& operator*() const { return *p; }
};

//Next classes are provided to simplify use of counted_ptr
template<class Y> struct ctor_def {
   size_t size() { return sizeof(Y); }
   Y* make(void* p) { return new(p) Y; }
};

template<class Y> struct ctor_copy {
   const Y& y;
   ctor_copy(const Y& y_) :y(y_) {}
   size_t size() { return sizeof(Y); }
   Y* make(void* p) { return new(p) Y(y); }
};

template<class Y, class Arg> struct ctor_arg {
   const Arg& a;
   ctor_arg(const Arg& a_) :a(a_) {}
   size_t size() { return sizeof(Y); }
   Y* make(void* p) { return new(p) Y(a); }
};

template<class Y, class Arg1, class Arg2> struct ctor_arg2 {
   const Arg1& a1;
   const Arg2& a2;
   ctor_arg2(const Arg1& a1_, const Arg2& a2_) :a1(a1_), a2(a2_) {}
   size_t size() { return sizeof(Y); }
   Y* make(void* p) { return new(p) Y(a1 ,a2); }
};

// Here some examples how counted_ptr can be used.
struct A {
   virtual int value() = 0;
}

struct B: virtual A {
   int i;
   B(int i_): i(i_) {}
   virtual int value() { return i; }
}

struct C: virtual A {
   int i;
   C() :i(100) {}
   virtual int value() { return i * i; }
}

counted_ptr<A> create(bool flag) {
   if (flag) {
      return counted_ptr<A>(ctor_arg<B, int>(100));
        // object B will be created via B::B(int)
   }
   else {
      counted_ptr<A> p(ctor_def<C>());
        // C will be created via C::C();
      p->i = 50;
      return q;
   }
}

void test(vector<counted_ptr<A>>& v) {
   v.push_back(create(true));
   v.push_back(create(false));
   B b(-1);
   v.push_back(counted_ptr<A>(ctor_copy<B>(b)));
    // v[2] will contain B constructed from B::B(const B&)
}

------------------------- end of code example -----------
   By the way, in the example of counted_ptr use I never write any kind of
"new", because now memory management is totally hidden which give counted_ptr
additional safety.

So what do you think about this?


--
Regards, Igor Boukanov.
igor.boukanov@fi.uib.no
http://www.fi.uib.no/~boukanov/
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]