$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Greg Colvin (gcolvin_at_[hidden])
Date: 2000-10-02 15:35:14
PS.  Forgot operator[].  See below.
> > When I needed such a class, I created auto_array_ptr from auto_ptr (cut &
> > paste) and changed delete to delete [].
> > 
> > Inelegant? yes.
> > Quick & painless? yes.
> > Did it work? yes.
> > Would I rather see a version with a parameterized deleter function? Yes.
> 
> I just tried that, but discovered in testing that it would incorrectly
> convert from Derived[] to Base[].
> 
> Doh.
> 
> So parameterization on the deleter function is not enough for a correct
> auto_array_ptr.  What it seems to take is to remove the templatization of
> the constructor, assignment, and auto_ptr_ref members.  Following is the
> code so far, which (gasp! shudder!) requires a conforming C++ compiler.
> I've tested with EDG.  Boostification is left as an exercise for someone
> with more patience with Microsoft than I can muster amymore.
> 
> 
> 
> ///////////////////////////////////////////////////////////////////////////////
> namespace boost {
> 
>    class auto_ptr_base {
>       template<typename Y> friend struct auto_ptr;
>       template<typename Y> friend struct auto_array_ptr;
>       template<typename Y> friend struct auto_ptr_ref;
>       void* p;
>    };
> 
>    template <typename X> class auto_ptr_ref {
>       template<typename Y> friend struct auto_ptr;
>       template<typename Y> friend struct auto_array_ptr;
>       auto_ptr_ref(X* p, auto_ptr_base& r) : r(r), p(p) {}
>       X* release() const { r.p = 0; return p; }
>       auto_ptr_base& r;
>       X* const p;
>    };
> 
>    template<typename X> struct auto_ptr : auto_ptr_base  {
>       typedef X element_type;
> 
>       explicit auto_ptr(X* px =0) throw() { p = px; }
>       auto_ptr(auto_ptr& r) throw() { p = (void*)r.release(); }
>       template<typename Y> auto_ptr(auto_ptr<Y>& r) throw() {
>          X* px = r.release();
>          p = (void*)px;
>       }
>       auto_ptr& operator=(auto_ptr& r) throw() {
>          reset(r.release());
>          return *this;
>       }
>       template<typename Y> auto_ptr& operator=(auto_ptr<Y>& r) throw() {
>          reset(r.release());
>          return *this;
>       }
>       ~auto_ptr() { delete get(); }
> 
>       X& operator*() const throw() { return *get(); }
>       X* operator->() const throw() { return get(); }
> 
>       X* get() const throw() { return static_cast<X*>(p); }
>       X* release() throw() { X* px = get(); p = 0; return px; }
>       void reset(X* px=0) throw() { if (px != get()) delete get(), p = (void*)px; }
> 
>       auto_ptr(auto_ptr_ref<X> r) throw() {
>          p = (void*)r.release();
>       }
>       auto_ptr& operator=(auto_ptr_ref<X> r) throw() {
>          reset(r.release());
>          return *this;
>       }
>       template<typename Y> operator auto_ptr_ref<Y>() throw() {
>          return auto_ptr_ref<Y>(get(),*this);
>       }
>       template<typename Y> operator auto_ptr<Y>() throw() {
>          return auto_ptr<Y>(release());
>       }
>    };
>    
>    template<typename X> struct auto_array_ptr : auto_ptr_base  {
>       typedef X element_type;
> 
>       explicit auto_array_ptr(X* px =0) throw() { p = px; }
>       auto_array_ptr(auto_array_ptr& r) throw() { p = (void*)r.release(); }
>       auto_array_ptr& operator=(auto_array_ptr& r) throw() {
>          reset(r.release());
>          return *this;
>       }
>       ~auto_array_ptr() { delete[] get(); }
> 
<       X& operator*() const throw() { return *get(); }
<       X* operator->() const throw() { return get(); }
      X& operator[](int i) throw() { return get()[i]; }
      X operator[](int i) const throw() { return get()[i]; }
>       X* get() const throw() { return static_cast<X*>(p); }
>       X* release() throw() { X* px = get(); p = 0; return px; }
>       void reset(X* px=0) throw() { if (px != get()) delete[] get(), p = (void*)px; }
> 
>       auto_array_ptr(auto_ptr_ref<X> r) throw() {
>          p = (void*)r.release();
>       }
>       auto_array_ptr& operator=(auto_ptr_ref<X> r) throw() {
>          reset(r.release());
>          return *this;
>       }
>       operator auto_ptr_ref<X>() throw() {
>          return auto_ptr_ref<X>(get(),*this);
>       }
> 
>    };
> }
> 
> 
> 
> ///////////////////////////////////////////////////////////////////////////////
> #include <stdio.h>
> using namespace boost;
> 
> struct MemoryTracker
> {
>     MemoryTracker(void* newMem)
>         : memory(newMem), next(list) { list = this; }
> 
>     static bool StopTracking(void* oldMem) {
>         for ( MemoryTracker* p = list; p != 0; p = p->next ) {
>             if ( p->memory == oldMem ) {
>                 p->memory = 0;
>                 return true;
>             }
>         }
>         ++nFailure;
>         puts( "Bad delete" );
>         return false;
>     }
> 
>     static int CheckAllDeleted() {
>         for ( MemoryTracker* p = list; p != 0; p = p->next ) {
>             if ( p->memory != 0 )
>                 ++nFailure, puts("not deleted");
>         }
>         return nFailure;
>     }
> 
> private:
>    void* memory;
>    MemoryTracker* next;
>    static int nFailure;
>    static MemoryTracker* list; // linked list of all memory trackers
> };
> 
> int MemoryTracker::nFailure = 0;
> MemoryTracker* MemoryTracker::list = 0;
> 
> struct Base
> {
>    virtual ~Base() {}    // So we can delete a Derived through a Base*
> 
>    // To test passing auto_ptr<Derived> as auto_ptr<Base>
>    static void sink(auto_ptr<Base>) {}
> 
>    void* operator new(unsigned n) {
>       void* p = ::operator new(n);
>       new MemoryTracker(p);
>       return p;
>    }
> 
>    void operator delete(void* p) {
>       if (MemoryTracker::StopTracking( p ));
>          ::operator delete(p);
>    }
> 
>    char dummy; // force this class to occupy space
> };
> 
> // A dummy base class
> struct ForceOffset {
>    char dummy; // force this class to occupy space
> };
> 
> // Trying to force Derived and Base to have different addresses
> struct Derived : ForceOffset, Base {
>    // To test passing auto_ptr<Derived> as auto_ptr<Derived>
>    static void sink(auto_ptr<Derived>) {}
>    static void sink(auto_array_ptr<Derived>) {}
> 
>    char dummy; // force this class to occupy space
> };
> 
> auto_ptr<Derived> source() {
>    return auto_ptr<Derived>(new Derived);
> }
> 
> void test() {
>    // Test functionality with no conversions
>    auto_ptr<const Derived> p(source());
>    auto_ptr<const Derived> pp(p);
>    Derived::sink(source());
>    p = pp;
>    p = source();
> 
>    // Test functionality with Derived->base conversions
>    auto_ptr<const Base> q(source());
>    auto_ptr<const Base> qp(p);
> //   Base::sink(source());  // committee decided to leave this one broken
>    q = pp;
>    q = source();
> }
> 
> auto_array_ptr<Derived> array_source() {
>    return auto_array_ptr<Derived>(new Derived[3]);
> }
> 
> void array_test() {
> 
>    // Test functionality with no conversions
>    auto_array_ptr<Derived> p(array_source());
>    auto_array_ptr<Derived> pp(p);
>    Derived::sink(array_source());
>    p = pp;
>    p = array_source();
> 
>    // Test functionality with Derived->base conversions
> #if 1  // shouldn't compile, reset to 0 for runtime testing
>     auto_array_ptr<Base> q(array_source());
>     auto_array_ptr<Base> qp(p);
>     q = pp;
>     q = array_source();
> #endif
> 
> }
> 
> int main() {
>    test();
>    array_test();
>    return MemoryTracker::CheckAllDeleted();
> }
> 
> 
> 
> 
> 
> 
>