|
Boost : |
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();
> }
>
>
>
>
>
>
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk