This is the mail archive of the libstdc++@sourceware.cygnus.com mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

auto_ptr patch, second try


Well, I've finally found time for this ...

After carefully reading the library issues, I feel that I misunderstand
auto_ptr a bit less now :) Here's what I did:

    * First of all, I put in some _GLIBCPP_RESOLVE_LIB_DEFECTS tests, so that
      we can get both current standard and future correct (we hope) behaviour.
      Specifically, the scope where auto_ptr_ref is defined depends on this
      flag, and whether or not an operator= for auto_ptr_ref is defined.
      (I may have overdone this a bit, but in any case the auto_ptr tests
      pass with and without this flag -- which can't be said for a lot of other
      tests ...)

    * I changed auto_ptr::_M_ptr to a `void*'.
      Rationale: auto_ptr_ref must be able to change the auto_ptr member, so
      it must have a reference to it, and we can't give it a reference to the
      "real" type since there's only one template parameter.
      This has some consequences:
        - auto_ptr::get() does a static_cast from _M_ptr to the element type
        - other auto_ptr members call get() instead of using _M_ptr where the
          type is important.
        - auto_ptr::auto_ptr(auto_ptr<Tp1>) can't have a member initialization
          list because it must check that an implicit conversion exists from
          _Tp1* to _Tp*

    * The auto_ptr_ref constructor takes two parameters now: the result of
      auto_ptr::get() and a reference to auto_ptr::_M_ptr; The first checks
      for the required implicit conversion, the second is there so that 
      auto_ptr_ref::_M_release can set that pointer to 0.
      There's an open issue here about whether auto_ptr_ref should have two
      data members (as it does now), or have just the void*& and do a
      static_cast in _M_release. I haven't a strong opinion about that; I think
      it's mostly a question of whether the compiler can eliminate the data
      members when inlining the conversions.

    * The original pointer is not release()'d in auto_ptr::operator auto_ptr_ref
      (that's too soon, sayeth the standard), but in the constructor and 
      assignment operator from auto_ptr_ref.

So, here it is. Hope I haven't made too many stupid mistakes this time 'round.

    Brane


2000-06-26  Branko Cibej  <branko.cibej@hermes.si>

	* bits/std_memory.h (auto_ptr_ref): Reworked and defined only if
	_GLIBCPP_RESOLVE_LIB_DEFECTS.
	(auto_ptr): _M_ptr changed to void*.
	(suto_ptr::get): Cast _M_ptr to element type.
	(auto_ptr::auto_ptr(auto_ptr<Tp1>)): Test implicit convetsion.
	(auto_ptr::~auto_ptr): Use this->get() instead of _M_ptr.
	(auto_ptr::operator*): Likewise.
	(auto_ptr::operator->): Likewise.
	(auto_ptr::release): Likewise.
	(auto_ptr::reset): Likewise.
	(auto_ptr::auto_ptr(auto_ptr_ref)): Initialize from __ref._M_release.
	(auto_ptr::operator auto_ptr_rev<_Tp1>): Updated.
	Define nested auto_ptr_ref unless _GLIBCPP_RESOLVE_LIB_DEFECTS.
	Define operator=(auto_ptr_ref) if _GLIBCPP_RESOLVE_LIB_DEFECTS.


-- 
Branko Čibej                 <branko.cibej@hermes.si>
HERMES SoftLab, Litijska 51, 1000 Ljubljana, Slovenia
voice: (+386 1) 586 53 49     fax: (+386 1) 586 52 70
Index: bits/std_memory.h
===================================================================
RCS file: /cvs/gcc/egcs/libstdc++-v3/bits/std_memory.h,v
retrieving revision 1.1
diff -c -p -r1.1 std_memory.h
*** std_memory.h	2000/04/21 20:33:28	1.1
--- std_memory.h	2000/06/26 14:11:49
***************
*** 25,43 ****
  
  __STL_BEGIN_NAMESPACE
  
! #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \
       defined(__STL_MEMBER_TEMPLATES)
!  
!  template<class _Tp1> struct auto_ptr_ref {
!    _Tp1* _M_ptr;
!    auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
  };
  
! #endif
  
  template <class _Tp> class auto_ptr {
  private:
!   _Tp* _M_ptr;
  
  public:
    typedef _Tp element_type;
--- 25,52 ----
  
  __STL_BEGIN_NAMESPACE
  
! #ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
! # if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \
       defined(__STL_MEMBER_TEMPLATES)
! 
! template<typename _Tp> class auto_ptr_ref {
!   template<typename _Tp1> friend class auto_ptr;
!   _Tp* _M_ptr;
!   void*& _M_ptr_ref;
!   explicit auto_ptr_ref(_Tp* __p, void*& __r) __STL_NOTHROW
!     : _M_ptr(__p), _M_ptr_ref(__r) {}
!   _Tp* _M_release() const __STL_NOTHROW {
!     _M_ptr_ref = 0;
!     return _M_ptr;
!   }
  };
  
! # endif /* auto ptr conversions && member templates */
! #endif /* _GLIBCPP_RESOLVE_LIB_DEFECTS */
  
  template <class _Tp> class auto_ptr {
  private:
!   void* _M_ptr;
  
  public:
    typedef _Tp element_type;
*************** public:
*** 46,53 ****
    auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
  
  #ifdef __STL_MEMBER_TEMPLATES
!   template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
!     : _M_ptr(__a.release()) {}
  #endif /* __STL_MEMBER_TEMPLATES */
  
    auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
--- 55,64 ----
    auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
  
  #ifdef __STL_MEMBER_TEMPLATES
!   template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
!     _Tp* const __tmp = __a.release(); // Must have implicit conversion
!     _M_ptr = __tmp;
!   }
  #endif /* __STL_MEMBER_TEMPLATES */
  
    auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
*************** public:
*** 63,89 ****
    }
  #endif /* __STL_MEMBER_TEMPLATES */
  
!   ~auto_ptr() __STL_NOTHROW { delete _M_ptr; }
  
    _Tp& operator*() const __STL_NOTHROW {
!     return *_M_ptr;
    }
    _Tp* operator->() const __STL_NOTHROW {
!     return _M_ptr;
    }
    _Tp* get() const __STL_NOTHROW {
!     return _M_ptr;
    }
    _Tp* release() __STL_NOTHROW {
!     _Tp* __tmp = _M_ptr;
      _M_ptr = 0;
      return __tmp;
    }
    void reset(_Tp* __p = 0) __STL_NOTHROW {
!     if (__p != _M_ptr) {
!       delete _M_ptr;
        _M_ptr = __p;
!     }    
    }
  
    // According to the C++ standard, these conversions are required.  Most
--- 74,101 ----
    }
  #endif /* __STL_MEMBER_TEMPLATES */
  
!   ~auto_ptr() __STL_NOTHROW { delete this->get(); }
  
    _Tp& operator*() const __STL_NOTHROW {
!     return *this->get();
    }
    _Tp* operator->() const __STL_NOTHROW {
!     return this->get();
    }
    _Tp* get() const __STL_NOTHROW {
!     return static_cast<_Tp*>(_M_ptr);
    }
    _Tp* release() __STL_NOTHROW {
!     _Tp* const __tmp = this->get();
      _M_ptr = 0;
      return __tmp;
    }
    void reset(_Tp* __p = 0) __STL_NOTHROW {
!     _Tp* const __tmp = this->get();
!     if (__p != __tmp) {
!       delete __tmp;
        _M_ptr = __p;
!     }
    }
  
    // According to the C++ standard, these conversions are required.  Most
*************** public:
*** 94,113 ****
  #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \
      defined(__STL_MEMBER_TEMPLATES)
  
  public:
    auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
!     : _M_ptr(__ref._M_ptr) {}
  
    auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
!     if (__ref._M_ptr != this->get()) {
!       delete _M_ptr;
!       _M_ptr = __ref._M_ptr;
!     }
      return *this;
    }
  
    template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW 
!     { return auto_ptr_ref<_Tp>(this->release()); }
    template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
      { return auto_ptr<_Tp1>(this->release()); }
  
--- 106,138 ----
  #if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \
      defined(__STL_MEMBER_TEMPLATES)
  
+ # ifndef _GLIBCPP_RESOLVE_LIB_DEFECTS
+ private:
+   template<typename _Tp1> struct auto_ptr_ref {
+     _Tp1* _M_ptr;
+     void*& _M_ptr_ref;
+     explicit auto_ptr_ref(_Tp1* __p, void*& __r) __STL_NOTHROW
+       : _M_ptr(__p), _M_ptr_ref(__r) {}
+     _Tp1* _M_release() const __STL_NOTHROW {
+       _M_ptr_ref = 0;
+       return _M_ptr;
+     }
+   };
+ # endif /* !_GLIBCPP_RESOLVE_LIB_DEFECTS */
+ 
  public:
    auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
!     : _M_ptr(__ref._M_release()) {}
  
+ # ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
    auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
!     reset(__ref._M_release());
      return *this;
    }
+ # endif /* _GLIBCPP_RESOLVE_LIB_DEFECTS */
  
    template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW 
!     { return auto_ptr_ref<_Tp1>(this->get(), _M_ptr); }
    template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
      { return auto_ptr<_Tp1>(this->release()); }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]