This is the mail archive of the libstdc++@gcc.gnu.org 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]
Other format: [Raw text]

[libstdc++] patch for auto_ptr problems


Jack Reeves submitted a patch for two pre-3.0 problems; Kenny Simpson
noted that he had reported one of them in GNATS already, with the same
fix.  Benjmain approved the changes at the same time I was cleaning up
and documenting the whole file.  I've incorporated the fixes into the
cleanup below.

Tested on i696-pc-linux-gnu and committed to trunk.  I'm testing a branch
build now but expect no problems; once I've confirmed it I'll check it in
for 3.1.1 (the problems have always been there).


2002-07-03  Jack Reeves  <jackw_reeves@hotmail.com>
            Kenny Simpson  <theonetruekenny@yahoo.com>
            Phil Edwards  <pme@gcc.gnu.org>

	PR libstdc++/3946
	* testsuite/20_util/auto_ptr.cc (test08):  New test.
	* include/std/std_memory.h (auto_ref_ptr):  Make constructor explicit.
	(auto_ptr::operator auto_ptr_ref):  Fix typo.
	General reformatting and doxygenating of the whole file.


Index: testsuite/20_util/auto_ptr.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/20_util/auto_ptr.cc,v
retrieving revision 1.4
diff -u -3 -p -r1.4 auto_ptr.cc
--- testsuite/20_util/auto_ptr.cc	7 Aug 2001 03:38:27 -0000	1.4
+++ testsuite/20_util/auto_ptr.cc	3 Jul 2002 22:21:45 -0000
@@ -1,4 +1,4 @@
-// Copyright (C) 2000 Free Software Foundation
+// Copyright (C) 2000, 2002 Free Software Foundation
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -276,6 +276,21 @@ test07()
   return 0;
 }
 
+
+// http://gcc.gnu.org/ml/libstdc++/2002-07/msg00024.html
+struct Base{};
+struct Derived : public Base {};
+std::auto_ptr<Derived> conversiontest08()
+  { return std::auto_ptr<Derived>(new Derived); }
+
+void
+test08()
+{
+  std::auto_ptr<Base> ptr;
+  ptr = conversiontest08();
+}
+
+
 int 
 main()
 {
@@ -286,6 +301,7 @@ main()
   test05();
   test06();
   test07();
+  test08();
 
   return 0;
 }
Index: include/std/std_memory.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/std/std_memory.h,v
retrieving revision 1.4
diff -u -3 -p -r1.4 std_memory.h
--- include/std/std_memory.h	27 Mar 2002 21:41:36 -0000	1.4
+++ include/std/std_memory.h	3 Jul 2002 22:21:45 -0000
@@ -58,147 +58,314 @@
 #include <bits/stl_uninitialized.h>
 #include <bits/stl_raw_storage_iter.h>
 
+// Since this entire file is within namespace std, there's no reason to
+// waste two spaces along the left column.  Thus the leading indentation is
+// slightly violated from here on.
 namespace std
 {
+/**
+ *  @if maint
+ *  This is a helper function.  The unused second parameter exists to
+ *  permit the real get_temporary_buffer to use template parameter deduction.
+ *
+ *  XXX This should perhaps use the pool.
+ *  @endif
+*/
+template <typename _Tp>
+pair<_Tp*, ptrdiff_t>
+__get_temporary_buffer(ptrdiff_t __len, _Tp*)
+{
+  if (__len > ptrdiff_t(INT_MAX / sizeof(_Tp)))
+    __len = INT_MAX / sizeof(_Tp);
 
-  /**
-   *  @if maint
-   *  This is a helper function.  The unused second parameter exists to
-   *  permit the real get_temporary_buffer to use template parameter deduction.
-   *  @endif
-  */
-  template <class _Tp>
-  pair<_Tp*, ptrdiff_t> 
-  __get_temporary_buffer(ptrdiff_t __len, _Tp*)
-  {
-    if (__len > ptrdiff_t(INT_MAX / sizeof(_Tp)))
-      __len = INT_MAX / sizeof(_Tp);
-
-    while (__len > 0) {
-      _Tp* __tmp = (_Tp*) std::malloc((std::size_t)__len * sizeof(_Tp));
-      if (__tmp != 0)
-	return pair<_Tp*, ptrdiff_t>(__tmp, __len);
-      __len /= 2;
-    }
-
-    return pair<_Tp*, ptrdiff_t>((_Tp*)0, 0);
+  while (__len > 0) {
+    _Tp* __tmp = (_Tp*) std::malloc((std::size_t)__len * sizeof(_Tp));
+    if (__tmp != 0)
+      return pair<_Tp*, ptrdiff_t>(__tmp, __len);
+    __len /= 2;
   }
 
-  /**
-   *  @brief This is a mostly-useless wrapper around malloc().
-   *  @param  len  The number of objects of type Tp.
-   *  @return   See full description.
-   *
-   *  Reinventing the wheel, but this time with prettier spokes!
-   *
-   *  This function tries to obtain storage for @c len adjacent Tp objects.
-   *  The objects themselves are not constructed, of course.  A pair<> is
-   *  returned containing "the buffer s address and capacity (in the units of
-   *  sizeof(Tp)), or a pair of 0 values if no storage can be obtained."
-   *  Note that the capacity obtained may be less than that requested if the
-   *  memory is unavailable; you should compare len with the .second return
-   *  value.
-  */
-  template <class _Tp>
-  inline pair<_Tp*, ptrdiff_t> get_temporary_buffer(ptrdiff_t __len) {
+  return pair<_Tp*, ptrdiff_t>((_Tp*)0, 0);
+}
+
+/**
+ *  @brief This is a mostly-useless wrapper around malloc().
+ *  @param  len  The number of objects of type Tp.
+ *  @return   See full description.
+ *
+ *  Reinventing the wheel, but this time with prettier spokes!
+ *
+ *  This function tries to obtain storage for @c len adjacent Tp objects.
+ *  The objects themselves are not constructed, of course.  A pair<> is
+ *  returned containing "the buffer s address and capacity (in the units of
+ *  sizeof(Tp)), or a pair of 0 values if no storage can be obtained."
+ *  Note that the capacity obtained may be less than that requested if the
+ *  memory is unavailable; you should compare len with the .second return
+ *  value.
+*/
+template<typename _Tp>
+  inline pair<_Tp*,ptrdiff_t>
+  get_temporary_buffer(ptrdiff_t __len)
+  {
     return __get_temporary_buffer(__len, (_Tp*) 0);
   }
 
-  /**
-   *  @brief The companion to get_temporary_buffer().
-   *  @param  p  A buffer previously allocated by get_temporary_buffer.
-   *  @return   None.
-   *
-   *  Frees the memory pointed to by p.
-   */
-  template <class _Tp>
-  void return_temporary_buffer(_Tp* __p) {
+/**
+ *  @brief The companion to get_temporary_buffer().
+ *  @param  p  A buffer previously allocated by get_temporary_buffer.
+ *  @return   None.
+ *
+ *  Frees the memory pointed to by p.
+ */
+template<typename _Tp>
+  void
+  return_temporary_buffer(_Tp* __p)
+  {
     std::free(__p);
   }
 
 
-template <class _Tp1>
+/**
+ *  A wrapper class to provide auto_ptr with reference semantics.  For
+ *  example, an auto_ptr can be assigned (or constructed from) the result of
+ *  a function which returns an auto_ptr by value.
+ *
+ *  All the auto_ptr_ref stuff should happen behind the scenes.
+*/
+template<typename _Tp1>
   struct auto_ptr_ref
 {
    _Tp1* _M_ptr;
-   auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
+
+   explicit
+   auto_ptr_ref(_Tp1* __p)
+   : _M_ptr(__p) {}
 };
 
+
 /**
- *  A simple smart pointer providing strict ownership semantics.  (More later.)
+ *  @brief  A simple smart pointer providing strict ownership semantics.
+ *
+ *  The Standard says:
+ *  <pre>
+ *  An @c auto_ptr owns the object it holds a pointer to.  Copying an
+ *  @c auto_ptr copies the pointer and transfers ownership to the destination.
+ *  If more than one @c auto_ptr owns the same object at the same time the
+ *  behavior of the program is undefined.
+ *
+ *  The uses of @c auto_ptr include providing temporary exception-safety for
+ *  dynamically allocated memory, passing ownership of dynamically allocated
+ *  memory to a function, and returning dynamically allocated memory from a
+ *  function.  @c auto_ptr does not meet the CopyConstructible and Assignable
+ *  requirements for Standard Library <a href="tables.html#65">container</a>
+ *  elements and thus instantiating a Standard Library container with an
+ *  @c auto_ptr results in undefined behavior.
+ *  </pre>
+ *  Quoted from [20.4.5]/3.
+ *
+ *  Good examples of what can and cannot be done with auto_ptr can be found
+ *  in the libstdc++ testsuite.
+ *
+ *  @if maint
+ *  _GLIBCPP_RESOLVE_LIB_DEFECTS
+ *  127.  auto_ptr<> conversion issues
+ *  These resolutions have all been incorporated.
+ *  @endif
 */
-template <class _Tp>
+template<typename _Tp>
   class auto_ptr
 {
 private:
   _Tp* _M_ptr;
 
 public:
+  /// The pointed-to type.
   typedef _Tp element_type;
 
-  explicit auto_ptr(_Tp* __p = 0) throw() : _M_ptr(__p) {}
-  auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) {}
+  /**
+   *  @brief  An %auto_ptr is usually constructed from a raw pointer.
+   *  @param  p  A pointer (defaults to NULL).
+   *
+   *  This object now @e owns the object pointed to by @a p.
+  */
+  explicit
+  auto_ptr(element_type* __p = 0) throw()
+  : _M_ptr(__p) { }
 
-  template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) throw()
-    : _M_ptr(__a.release()) {}
+  /**
+   *  @brief  An %auto_ptr can be constructed from another %auto_ptr.
+   *  @param  a  Another %auto_ptr of the same type.
+   *
+   *  This object now @e owns the object previously owned by @a a, which has
+   *  given up ownsership.
+  */
+  auto_ptr(auto_ptr& __a) throw()
+  : _M_ptr(__a.release()) { }
 
-  auto_ptr& operator=(auto_ptr& __a) throw() {
-    reset(__a.release());
-    return *this;
-  }
+  /**
+   *  @brief  An %auto_ptr can be constructed from another %auto_ptr.
+   *  @param  a  Another %auto_ptr of a different but related type.
+   *
+   *  A pointer-to-Tp1 must be convertible to a pointer-to-Tp/element_type.
+   *
+   *  This object now @e owns the object previously owned by @a a, which has
+   *  given up ownsership.
+  */
+  template<typename _Tp1>
+    auto_ptr(auto_ptr<_Tp1>& __a) throw()
+    : _M_ptr(__a.release()) { }
 
-  template <class _Tp1>
-  auto_ptr& operator=(auto_ptr<_Tp1>& __a) throw() {
-    reset(__a.release());
-    return *this;
-  }
-  
-  // Note: The C++ standard says there is supposed to be an empty throw
-  // specification here, but omitting it is standard conforming.  Its 
-  // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
-  // this is prohibited.
+  /**
+   *  @brief  %auto_ptr assignment operator.
+   *  @param  a  Another %auto_ptr of the same type.
+   *
+   *  This object now @e owns the object previously owned by @a a, which has
+   *  given up ownsership.  The object that this one @e used to own and
+   *  track has been deleted.
+  */
+  auto_ptr&
+  operator=(auto_ptr& __a) throw()
+    {
+      reset(__a.release());
+      return *this;
+    }
+
+  /**
+   *  @brief  %auto_ptr assignment operator.
+   *  @param  a  Another %auto_ptr of a different but related type.
+   *
+   *  A pointer-to-Tp1 must be convertible to a pointer-to-Tp/element_type.
+   *
+   *  This object now @e owns the object previously owned by @a a, which has
+   *  given up ownsership.  The object that this one @e used to own and
+   *  track has been deleted.
+  */
+  template <typename _Tp1>
+    auto_ptr&
+    operator=(auto_ptr<_Tp1>& __a) throw()
+    {
+      reset(__a.release());
+      return *this;
+    }
+
+  /**
+   *  When the %auto_ptr goes out of scope, the object it owns is deleted.
+   *  If it no longer owns anything (i.e., @c get() is @c NULL), then this
+   *  has no effect.
+   *
+   *  @if maint
+   *  The C++ standard says there is supposed to be an empty throw
+   *  specification here, but omitting it is standard conforming.  Its
+   *  presence can be detected only if _Tp::~_Tp() throws, but this is
+   *  prohibited.  [17.4.3.6]/2
+   *  @end maint
+  */
   ~auto_ptr() { delete _M_ptr; }
- 
-  _Tp& operator*() const throw() {
-    return *_M_ptr;
-  }
-  _Tp* operator->() const throw() {
-    return _M_ptr;
-  }
-  _Tp* get() const throw() {
-    return _M_ptr;
-  }
-  _Tp* release() throw() {
-    _Tp* __tmp = _M_ptr;
-    _M_ptr = 0;
-    return __tmp;
-  }
-  void reset(_Tp* __p = 0) throw() {
-    if (__p != _M_ptr) {
-      delete _M_ptr;
-      _M_ptr = __p;
-    }    
-  }
 
-public:
-  auto_ptr(auto_ptr_ref<_Tp> __ref) throw()
+  /**
+   *  @brief  Smart pointer dereferencing.
+   *
+   *  If this %auto_ptr no longer owns anything, then this operation will
+   *  crash.  (For a smart pointer, "no longer owns anything" is the same as
+   *  being a null pointer, and you know what happens when you dereference
+   *  one of those...)
+  */
+  element_type&
+  operator*() const throw() { return *_M_ptr; }
+
+  /**
+   *  @brief  Smart pointer dereferencing.
+   *
+   *  This returns the pointer itself, which the language then will
+   *  automatically cause to be dereferenced.
+  */
+  element_type*
+  operator->() const throw() { return _M_ptr; }
+
+  /**
+   *  @brief  Bypassing the smart pointer.
+   *  @return  The raw pointer being managed.
+   *
+   *  You can get a copy of the pointer that this object owns, for
+   *  situations such as passing to a function which only accepts a raw
+   *  pointer.
+   *
+   *  @note  This %auto_ptr still owns the memory.
+  */
+  element_type*
+  get() const throw() { return _M_ptr; }
+
+  /**
+   *  @brief  Bypassing the smart pointer.
+   *  @return  The raw pointer being managed.
+   *
+   *  You can get a copy of the pointer that this object owns, for
+   *  situations such as passing to a function which only accepts a raw
+   *  pointer.
+   *
+   *  @note  This %auto_ptr no longer owns the memory.  When this object
+   *  goes out of scope, nothing will happen.
+  */
+  element_type*
+  release() throw()
+    {
+      element_type* __tmp = _M_ptr;
+      _M_ptr = 0;
+      return __tmp;
+    }
+
+  /**
+   *  @brief  Forcibly deletes the managed object.
+   *  @param  p  A pointer (defaults to NULL).
+   *
+   *  This object now @e owns the object pointed to by @a p.  The previous
+   *  object has been deleted.
+  */
+  void
+  reset(element_type* __p = 0) throw()
+    {
+      if (__p != _M_ptr)
+        {
+          delete _M_ptr;
+          _M_ptr = __p;
+        }
+    }
+
+  /** @{
+   *  @brief  Automatic conversions
+   *
+   *  These operations convert an %auto_ptr into and from an auto_ptr_ref
+   *  automatically as needed.  This allows constructs such as
+   *  @code
+   *    auto_ptr<Derived>  func_returning_auto_ptr(.....);
+   *    ...
+   *    auto_ptr<Base> ptr = func_returning_auto_ptr(.....);
+   *  @endcode
+  */
+  auto_ptr(auto_ptr_ref<element_type> __ref) throw()
     : _M_ptr(__ref._M_ptr) {}
 
-  auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) throw() {
-    if (__ref._M_ptr != this->get()) {
-      delete _M_ptr;
-      _M_ptr = __ref._M_ptr;
+  auto_ptr&
+  operator=(auto_ptr_ref<element_type> __ref) throw()
+    {
+      if (__ref._M_ptr != this->get())
+        {
+          delete _M_ptr;
+          _M_ptr = __ref._M_ptr;
+        }
+      return *this;
     }
-    return *this;
-  }
 
-  template <class _Tp1> operator auto_ptr_ref<_Tp1>() throw() 
-    { return auto_ptr_ref<_Tp>(this->release()); }
-  template <class _Tp1> operator auto_ptr<_Tp1>() throw()
-    { return auto_ptr<_Tp1>(this->release()); }
+  template<typename _Tp1>
+    operator auto_ptr_ref<_Tp1>() throw()
+      { return auto_ptr_ref<_Tp1>(this->release()); }
+
+  template<typename _Tp1>
+    operator auto_ptr<_Tp1>() throw()
+      { return auto_ptr<_Tp1>(this->release()); }
+  /** @}  */
 };
 
 } // namespace std
 
 #endif /* _CPP_MEMORY */
-


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