diff mbox series

[committed] Add gnu::unique_ptr

Message ID 1508187336-32666-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series [committed] Add gnu::unique_ptr | expand

Commit Message

David Malcolm Oct. 16, 2017, 8:55 p.m. UTC
From: Trevor Saunders <tbsaunde+gcc@tbsaunde.org>

On Mon, 2017-10-16 at 11:47 +0100, Pedro Alves wrote:
> On 10/14/2017 12:35 AM, David Malcolm wrote:
> 
> > As far as I can tell from your mail, the one issue that blocks that
> > is the lack of gdb::unique_xmalloc_ptr<T[]>.
> > 
> > So here's an patch on top of the previous one which adds the
> > xmalloc_deleter<T[]> (taken from gdb, but changing "xfree" to
> > "free", and adding support for pre-C++11 dialects), along with
> > selftests for unique_ptr<T[]>, unique_xmalloc_ptr<T> and
> > unique_xmalloc_ptr<T[]>.
> 
> Thanks much!
> 
> > As before, successfully bootstrapped & regrtested on x86_64-pc-
> > linux-gnu,
> > using gcc 4.8 for the initial bootstrap (hence testing both gnu++03
> > then gnu++14 in the selftests, for stage 1 and stages 2 and 3
> > respectively).
> > 
> 
> Excellent.
> 
> > Hand-tested with "make selftest-valgrind" with both gnu++03 and
> > gnu++14.
> > 
> > Also tested stage1 on powerpc-ibm-aix7.1.3.0 ("gcc111" in the
> > compile farm; gcc 4.8 i.e. gnu++03)
> > 
> > Is this OK?
> 
> Looks great to me.
> 
> > +/* Verify that gnu::unique_malloc_ptr works.  */
> 
> Typo: malloc -> xmalloc.  Appears in other comments too.
> 
> Thanks,
> Pedro Alves

Thanks.  I've fixed those typos, re-tested, and committed it to
gcc trunk as r253797.

For reference, here's what I committed:


This is a version of the patch posted by Trevor Saunders on 2017-07-31,
for which he wrote:
> For most of the history of this see
>   https://sourceware.org/ml/gdb-patches/2016-10/msg00223.html
> The changes are mostly s/gdb/gtl/g

This version was updated by me (dmalcolm) adding these changes:
- renaming of "gtl" to "gnu" (3 letters, and one of the ones Richi
  proposed, and not a match for "*tl")
- renaming of DEFINE_GDB_UNIQUE_PTR to DEFINE_GNU_UNIQUE_PTR
- renaming of xfree_deleter to xmalloc_deleter, and making it
  use "free" rather than "xfree" (which doesn't exist)
- added a gcc/unique-ptr-tests.cc
- implement unique_xmalloc_ptr<T[]> (taken from gdb, but changing
  "xfree" to "free", and adding support for pre-C++-11)

gcc/ChangeLog:

	David Malcolm <dmalcolm@redhat.com>

	* Makefile.in (OBJS): Add unique-ptr-tests.o.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::unique_ptr_tests_cc_tests.
	* selftest.h (selftest::unique_ptr_tests_cc_tests): New decl.
	* unique-ptr-tests.cc: New file.

include/ChangeLog:

	Trevor Saunders  <tbsaunde+gcc@tbsaunde.org>
	David Malcolm <dmalcolm@redhat.com>

	* unique-ptr.h: New file.
---
 gcc/Makefile.in          |   1 +
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 gcc/unique-ptr-tests.cc  | 234 +++++++++++++++++++++++++++
 include/unique-ptr.h     | 403 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 640 insertions(+)
 create mode 100644 gcc/unique-ptr-tests.cc
 create mode 100644 include/unique-ptr.h

Comments

Gerald Pfeifer Oct. 19, 2017, 5:23 p.m. UTC | #1
On Mon, 16 Oct 2017, David Malcolm wrote:
> For reference, here's what I committed:

I'm afraid this may have broken the bootstrap with clang?

In file included from /scratch/tmp/gerald/gcc-HEAD/gcc/unique-ptr-tests.cc:23:
In file included from /scratch/tmp/gerald/gcc-HEAD/gcc/../include/unique-ptr.h:77:
In file included from /usr/include/c++/v1/memory:629:
/usr/include/c++/v1/typeinfo:199:2: error: no member named 'fancy_abort' in namespace 'std::__1'; did you mean simply 'fancy_abort'?
        _VSTD::abort();
        ^~~~~~~
/usr/include/c++/v1/__config:390:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
              ^
/scratch/tmp/gerald/gcc-HEAD/gcc/system.h:725:13: note: 'fancy_abort' declared here
extern void fancy_abort (const char *, int, const char *)
            ^


This is FreeBSD clang version 4.0.0 (tags/RELEASE_400/final 297347) 
(based on LLVM 4.0.0), on x86_64-unknown-freebsd11.1.

Gerald
David Malcolm Oct. 19, 2017, 5:27 p.m. UTC | #2
On Thu, 2017-10-19 at 19:23 +0200, Gerald Pfeifer wrote:
> On Mon, 16 Oct 2017, David Malcolm wrote:
> > For reference, here's what I committed:
> 
> I'm afraid this may have broken the bootstrap with clang?
> 
> In file included from /scratch/tmp/gerald/gcc-HEAD/gcc/unique-ptr-
> tests.cc:23:
> In file included from /scratch/tmp/gerald/gcc-
> HEAD/gcc/../include/unique-ptr.h:77:
> In file included from /usr/include/c++/v1/memory:629:
> /usr/include/c++/v1/typeinfo:199:2: error: no member named
> 'fancy_abort' in namespace 'std::__1'; did you mean simply
> 'fancy_abort'?
>         _VSTD::abort();
>         ^~~~~~~
> /usr/include/c++/v1/__config:390:15: note: expanded from macro
> '_VSTD'
> #define _VSTD std::_LIBCPP_NAMESPACE
>               ^
> /scratch/tmp/gerald/gcc-HEAD/gcc/system.h:725:13: note: 'fancy_abort'
> declared here
> extern void fancy_abort (const char *, int, const char *)
>             ^
> 
> 
> This is FreeBSD clang version 4.0.0 (tags/RELEASE_400/final 297347) 
> (based on LLVM 4.0.0), on x86_64-unknown-freebsd11.1.
> 
> Gerald

Sorry about the breakage.

There seem to have been similar problems on OS X:
  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82610

The proposed fix there is to include <memory> in system.h, which
presumably would fix this also.
Gerald Pfeifer Oct. 22, 2017, 7:28 a.m. UTC | #3
On Thu, 19 Oct 2017, David Malcolm wrote:
>> In file included from /scratch/tmp/gerald/gcc-HEAD/gcc/unique-ptr-tests.cc:23:
>> In file included from /scratch/tmp/gerald/gcc-HEAD/gcc/../include/unique-ptr.h:77:
>> In file included from /usr/include/c++/v1/memory:629:
>> /usr/include/c++/v1/typeinfo:199:2: error: no member named
>> 'fancy_abort' in namespace 'std::__1'; did you mean simply 'fancy_abort'?
>>         _VSTD::abort();
>>         ^~~~~~~
>> /usr/include/c++/v1/__config:390:15: note: expanded from macro '_VSTD'
>> #define _VSTD std::_LIBCPP_NAMESPACE
> There seem to have been similar problems on OS X:
>   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82610

Yes, I believe it's the same actually (unearthed by clang as system
compiler).

> The proposed fix there is to include <memory> in system.h, which
> presumably would fix this also.

That appears to work around the bootstrap failure on my tester as
well.

How can we go about fixing this in the tree?

Gerald
diff mbox series

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 878ce7b..2809619 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1568,6 +1568,7 @@  OBJS = \
 	tree-vrp.o \
 	tree.o \
 	typed-splay-tree.o \
+	unique-ptr-tests.o \
 	valtrack.o \
 	value-prof.o \
 	var-tracking.o \
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 30e476d..b05e0fc 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -66,6 +66,7 @@  selftest::run_tests ()
   sreal_c_tests ();
   fibonacci_heap_c_tests ();
   typed_splay_tree_c_tests ();
+  unique_ptr_tests_cc_tests ();
 
   /* Mid-level data structures.  */
   input_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 96eccac..adc0b68 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -194,6 +194,7 @@  extern void store_merging_c_tests ();
 extern void typed_splay_tree_c_tests ();
 extern void tree_c_tests ();
 extern void tree_cfg_c_tests ();
+extern void unique_ptr_tests_cc_tests ();
 extern void vec_c_tests ();
 extern void wide_int_cc_tests ();
 extern void predict_c_tests ();
diff --git a/gcc/unique-ptr-tests.cc b/gcc/unique-ptr-tests.cc
new file mode 100644
index 0000000..f5b72a8
--- /dev/null
+++ b/gcc/unique-ptr-tests.cc
@@ -0,0 +1,234 @@ 
+/* Unit tests for unique-ptr.h.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "unique-ptr.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+namespace {
+
+/* A class for counting ctor and dtor invocations.  */
+
+struct stats
+{
+  stats () : ctor_count (0), dtor_count (0) {}
+
+  int ctor_count;
+  int dtor_count;
+};
+
+/* A class that uses "stats" to track its ctor and dtor invocations.  */
+
+class foo
+{
+public:
+  foo (stats &s) : m_s (s) { ++m_s.ctor_count; }
+  ~foo () { ++m_s.dtor_count; }
+
+  int example_method () const { return 42; }
+
+private:
+  foo (const foo&);
+  foo & operator= (const foo &);
+
+private:
+  stats &m_s;
+};
+
+/* A struct for testing unique_ptr<T[]>.  */
+
+struct has_default_ctor
+{
+  has_default_ctor () : m_field (42) {}
+  int m_field;
+};
+
+/* A dummy struct for testing unique_xmalloc_ptr.  */
+
+struct dummy
+{
+  int field;
+};
+
+} // anonymous namespace
+
+/* Verify that the default ctor inits ptrs to NULL.  */
+
+static void
+test_null_ptr ()
+{
+  gnu::unique_ptr<void *> p;
+  ASSERT_EQ (NULL, p);
+
+  gnu::unique_xmalloc_ptr<void *> q;
+  ASSERT_EQ (NULL, q);
+}
+
+/* Verify that deletion happens when a unique_ptr goes out of scope.  */
+
+static void
+test_implicit_deletion ()
+{
+  stats s;
+  ASSERT_EQ (0, s.ctor_count);
+  ASSERT_EQ (0, s.dtor_count);
+
+  {
+    gnu::unique_ptr<foo> f (new foo (s));
+    ASSERT_NE (NULL, f);
+    ASSERT_EQ (1, s.ctor_count);
+    ASSERT_EQ (0, s.dtor_count);
+  }
+
+  /* Verify that the foo was implicitly deleted.  */
+  ASSERT_EQ (1, s.ctor_count);
+  ASSERT_EQ (1, s.dtor_count);
+}
+
+/* Verify that we can assign to a NULL unique_ptr.  */
+
+static void
+test_overwrite_of_null ()
+{
+  stats s;
+  ASSERT_EQ (0, s.ctor_count);
+  ASSERT_EQ (0, s.dtor_count);
+
+  {
+    gnu::unique_ptr<foo> f;
+    ASSERT_EQ (NULL, f);
+    ASSERT_EQ (0, s.ctor_count);
+    ASSERT_EQ (0, s.dtor_count);
+
+    /* Overwrite with a non-NULL value.  */
+    f = gnu::unique_ptr<foo> (new foo (s));
+    ASSERT_EQ (1, s.ctor_count);
+    ASSERT_EQ (0, s.dtor_count);
+  }
+
+  /* Verify that the foo is implicitly deleted.  */
+  ASSERT_EQ (1, s.ctor_count);
+  ASSERT_EQ (1, s.dtor_count);
+}
+
+/* Verify that we can assign to a non-NULL unique_ptr.  */
+
+static void
+test_overwrite_of_non_null ()
+{
+  stats s;
+  ASSERT_EQ (0, s.ctor_count);
+  ASSERT_EQ (0, s.dtor_count);
+
+  {
+    gnu::unique_ptr<foo> f (new foo (s));
+    ASSERT_NE (NULL, f);
+    ASSERT_EQ (1, s.ctor_count);
+    ASSERT_EQ (0, s.dtor_count);
+
+    /* Overwrite with a different value.  */
+    f = gnu::unique_ptr<foo> (new foo (s));
+    ASSERT_EQ (2, s.ctor_count);
+    ASSERT_EQ (1, s.dtor_count);
+  }
+
+  /* Verify that the 2nd foo was implicitly deleted.  */
+  ASSERT_EQ (2, s.ctor_count);
+  ASSERT_EQ (2, s.dtor_count);
+}
+
+/* Verify that unique_ptr's overloaded ops work.  */
+
+static void
+test_overloaded_ops ()
+{
+  stats s;
+  gnu::unique_ptr<foo> f (new foo (s));
+  ASSERT_EQ (42, f->example_method ());
+  ASSERT_EQ (42, (*f).example_method ());
+  ASSERT_EQ (f, f);
+  ASSERT_NE (NULL, f.get ());
+
+  gnu::unique_ptr<foo> g (new foo (s));
+  ASSERT_NE (f, g);
+}
+
+/* Verify that the gnu::unique_ptr specialization for T[] works.  */
+
+static void
+test_array_new ()
+{
+  const int num = 10;
+  gnu::unique_ptr<has_default_ctor[]> p (new has_default_ctor[num]);
+  ASSERT_NE (NULL, p.get ());
+  /* Verify that operator[] works, and that the default ctor was called
+     on each element.  */
+  for (int i = 0; i < num; i++)
+    ASSERT_EQ (42, p[i].m_field);
+}
+
+/* Verify that gnu::unique_xmalloc_ptr works.  */
+
+static void
+test_xmalloc ()
+{
+  gnu::unique_xmalloc_ptr<dummy> p (XNEW (dummy));
+  ASSERT_NE (NULL, p.get ());
+}
+
+/* Verify the gnu::unique_xmalloc_ptr specialization for T[].  */
+
+static void
+test_xmalloc_array ()
+{
+  const int num = 10;
+  gnu::unique_xmalloc_ptr<dummy[]> p (XNEWVEC (dummy, num));
+  ASSERT_NE (NULL, p.get ());
+
+  /* Verify that operator[] works.  */
+  for (int i = 0; i < num; i++)
+    p[i].field = 42;
+  for (int i = 0; i < num; i++)
+    ASSERT_EQ (42, p[i].field);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+unique_ptr_tests_cc_tests ()
+{
+  test_null_ptr ();
+  test_implicit_deletion ();
+  test_overwrite_of_null ();
+  test_overwrite_of_non_null ();
+  test_overloaded_ops ();
+  test_array_new ();
+  test_xmalloc ();
+  test_xmalloc_array ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/include/unique-ptr.h b/include/unique-ptr.h
new file mode 100644
index 0000000..c5ca031
--- /dev/null
+++ b/include/unique-ptr.h
@@ -0,0 +1,403 @@ 
+/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03.
+
+   Copyright (C) 2007-2016 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* gnu::unique_ptr defines a C++ owning smart pointer that exposes a
+   subset of the std::unique_ptr API.
+
+   In fact, when compiled with a C++11 compiler, gnu::unique_ptr
+   actually _is_ std::unique_ptr.  When compiled with a C++03 compiler
+   OTOH, it's an hand coded std::unique_ptr emulation that assumes
+   code is correct and doesn't try to be too smart.
+
+   This supports custom deleters, but not _stateful_ deleters, so you
+   can't use those in C++11 mode either.  Only the managed pointer is
+   stored in the smart pointer.  That could be changed; it simply
+   wasn't found necessary.
+
+   At the end of the file you'll find a gnu::unique_ptr partial
+   specialization that uses a custom (stateless) deleter:
+   gnu::unique_xmalloc_ptr.  That is used to manage pointers to
+   objects allocated with xmalloc.
+
+   The C++03 version was originally based on GCC 7.0's std::auto_ptr
+   and then heavily customized to behave more like C++11's
+   std::unique_ptr, but at this point, it no longer shares much at all
+   with the original file.  But, that's the history and the reason for
+   the copyright's starting year.
+
+   The C++03 version lets you shoot yourself in the foot, since
+   similarly to std::auto_ptr, the copy constructor and assignment
+   operators actually move.  Also, in the name of simplicity, no
+   effort is spent on using SFINAE to prevent invalid conversions,
+   etc.  This is not really a problem, because the goal here is to
+   allow code that would be correct using std::unique_ptr to be
+   equally correct in C++03 mode, and, just as efficient.  If client
+   code compiles correctly with a C++11 (or newer) compiler, we know
+   we're not doing anything invalid by mistake.
+
+   Usage notes:
+
+   - Putting gnu::unique_ptr in standard containers is not supported,
+     since C++03 containers are not move-aware (and our emulation
+     relies on copy actually moving).
+
+   - Since there's no nullptr in C++03, gnu::unique_ptr allows
+     implicit initialization and assignment from NULL instead.
+
+   - To check whether there's an associated managed object, all these
+     work as expected:
+
+      if (ptr)
+      if (!ptr)
+      if (ptr != NULL)
+      if (ptr == NULL)
+      if (NULL != ptr)
+      if (NULL == ptr)
+*/
+
+#ifndef GNU_UNIQUE_PTR_H
+#define GNU_UNIQUE_PTR_H 1
+
+#include <memory>
+
+namespace gnu
+{
+
+#if __cplusplus >= 201103
+
+/* In C++11 mode, all we need is import the standard
+   std::unique_ptr.  */
+template<typename T> using unique_ptr = std::unique_ptr<T>;
+
+/* Pull in move as well.  */
+using std::move;
+
+#else /* C++11 */
+
+/* Default destruction policy used by gnu::unique_ptr when no deleter
+   is specified.  Uses delete.  */
+
+template<typename T>
+struct default_delete
+{
+  void operator () (T *ptr) const { delete ptr; }
+};
+
+/* Specialization for arrays.  Uses delete[].  */
+
+template<typename T>
+struct default_delete<T[]>
+{
+  void operator () (T *ptr) const { delete [] ptr; }
+};
+
+namespace detail
+{
+/* Type used to support implicit construction from NULL:
+
+     gnu::unique_ptr<foo> func (....)
+     {
+     return NULL;
+     }
+
+   and assignment from NULL:
+
+     gnu::unique_ptr<foo> ptr (....);
+     ...
+     ptr = NULL;
+
+  It is intentionally not defined anywhere.  */
+struct nullptr_t;
+
+/* Base class of our unique_ptr emulation.  Contains code common to
+   both unique_ptr<T, D> and unique_ptr<T[], D>.  */
+
+template<typename T, typename D>
+class unique_ptr_base
+{
+public:
+  typedef T *pointer;
+  typedef T element_type;
+  typedef D deleter_type;
+
+  /* Takes ownership of a pointer.  P is a pointer to an object of
+     element_type type.  Defaults to NULL.  */
+  explicit unique_ptr_base (element_type *p = NULL) throw () : m_ptr (p) {}
+
+  /* The "move" constructor.  Really a copy constructor that actually
+     moves.  Even though std::unique_ptr is not copyable, our little
+     simpler emulation allows it, because:
+
+       - There are no rvalue references in C++03.  Our move emulation
+       instead relies on copy/assignment moving, like std::auto_ptr.
+       - RVO/NRVO requires an accessible copy constructor
+  */
+  unique_ptr_base (const unique_ptr_base &other) throw ()
+    : m_ptr (const_cast<unique_ptr_base &> (other).release ()) {}
+
+  /* Converting "move" constructor.  Really an lvalue ref converting
+     constructor that actually moves.  This allows constructs such as:
+
+      unique_ptr<Derived> func_returning_unique_ptr (.....);
+      ...
+      unique_ptr<Base> ptr = func_returning_unique_ptr (.....);
+  */
+  template<typename T1, typename D1>
+  unique_ptr_base (const unique_ptr_base<T1, D1> &other) throw ()
+    : m_ptr (const_cast<unique_ptr_base<T1, D1> &> (other).release ()) {}
+
+  /* The "move" assignment operator.  Really an lvalue ref copy
+     assignment operator that actually moves.  See comments above.  */
+  unique_ptr_base &operator= (const unique_ptr_base &other) throw ()
+  {
+    reset (const_cast<unique_ptr_base &> (other).release ());
+    return *this;
+  }
+
+  /* Converting "move" assignment.  Really an lvalue ref converting
+     copy assignment operator that moves.  See comments above.  */
+  template<typename T1, typename D1>
+  unique_ptr_base &operator= (const unique_ptr_base<T1, D1> &other) throw ()
+  {
+    reset (const_cast<unique_ptr_base<T1, D1> &> (other).release ());
+    return *this;
+  }
+
+  /* std::unique_ptr does not allow assignment, except from nullptr.
+     nullptr doesn't exist in C++03, so we allow assignment from NULL
+     instead [ptr = NULL;].
+  */
+  unique_ptr_base &operator= (detail::nullptr_t *) throw ()
+  {
+    reset ();
+    return *this;
+  }
+
+  ~unique_ptr_base () { call_deleter (); }
+
+  /* "explicit operator bool ()" emulation using the safe bool
+     idiom.  */
+private:
+  typedef void (unique_ptr_base::*explicit_operator_bool) () const;
+  void this_type_does_not_support_comparisons () const {}
+
+public:
+  operator explicit_operator_bool () const
+  {
+    return (m_ptr != NULL
+	    ? &unique_ptr_base::this_type_does_not_support_comparisons
+	    : 0);
+  }
+
+  element_type *get () const throw () { return m_ptr; }
+
+  element_type *release () throw ()
+  {
+    pointer tmp = m_ptr;
+    m_ptr = NULL;
+    return tmp;
+  }
+
+  void reset (element_type *p = NULL) throw ()
+  {
+    if (p != m_ptr)
+      {
+	call_deleter ();
+	m_ptr = p;
+      }
+  }
+
+private:
+
+  /* Call the deleter.  Note we assume the deleter is "stateless".  */
+  void call_deleter ()
+  {
+    D d;
+
+    d (m_ptr);
+  }
+
+  element_type *m_ptr;
+};
+
+} /* namespace detail */
+
+/* Macro used to create a unique_ptr_base "partial specialization" --
+   a subclass that uses a specific deleter.  Basically this re-defines
+   the necessary constructors.  This is necessary because C++03
+   doesn't support inheriting constructors with "using".  While at it,
+   we inherit the assignment operator.  TYPE is the name of the type
+   being defined.  Assumes that 'base_type' is a typedef of the
+   baseclass TYPE is inheriting from.  */
+#define DEFINE_GNU_UNIQUE_PTR(TYPE)						\
+public:									\
+  explicit TYPE (T *p = NULL) throw ()					\
+    : base_type (p) {}							\
+									\
+  TYPE (const TYPE &other) throw () : base_type (other) {}		\
+									\
+  TYPE (detail::nullptr_t *) throw () : base_type (NULL) {}		\
+									\
+  template<typename T1, typename D1>					\
+  TYPE (const detail::unique_ptr_base<T1, D1> &other) throw ()		\
+    : base_type (other) {}						\
+									\
+  using base_type::operator=;
+
+/* Define single-object gnu::unique_ptr.  */
+
+template <typename T, typename D = default_delete<T> >
+class unique_ptr : public detail::unique_ptr_base<T, D>
+{
+  typedef detail::unique_ptr_base<T, D> base_type;
+
+  DEFINE_GNU_UNIQUE_PTR (unique_ptr)
+
+public:
+  /* Dereferencing.  */
+  T &operator* () const throw () { return *this->get (); }
+  T *operator-> () const throw () { return this->get (); }
+};
+
+/* Define gnu::unique_ptr specialization for T[].  */
+
+template <typename T, typename D>
+class unique_ptr<T[], D> : public detail::unique_ptr_base<T, D>
+{
+  typedef detail::unique_ptr_base<T, D> base_type;
+
+  DEFINE_GNU_UNIQUE_PTR (unique_ptr)
+
+public:
+  /* Indexing operator.  */
+  T &operator[] (size_t i) const { return this->get ()[i]; }
+};
+
+/* Comparison operators.  */
+
+template <typename T, typename D,
+	  typename U, typename E>
+inline bool
+operator== (const detail::unique_ptr_base<T, D> &x,
+	    const detail::unique_ptr_base<U, E> &y)
+{ return x.get() == y.get(); }
+
+template <typename T, typename D,
+	  typename U, typename E>
+inline bool
+operator!= (const detail::unique_ptr_base<T, D> &x,
+	    const detail::unique_ptr_base<U, E> &y)
+{ return x.get() != y.get(); }
+
+template<typename T, typename D,
+	 typename U, typename E>
+inline bool
+operator< (const detail::unique_ptr_base<T, D> &x,
+	   const detail::unique_ptr_base<U, E> &y)
+{ return x.get() < y.get (); }
+
+template<typename T, typename D,
+	 typename U, typename E>
+inline bool
+operator<= (const detail::unique_ptr_base<T, D> &x,
+	    const detail::unique_ptr_base<U, E> &y)
+{ return !(y < x); }
+
+template<typename T, typename D,
+	 typename U, typename E>
+inline bool
+operator> (const detail::unique_ptr_base<T, D> &x,
+	   const detail::unique_ptr_base<U, E> &y)
+{ return y < x; }
+
+template<typename T, typename D,
+	 typename U, typename E>
+inline bool
+operator>= (const detail::unique_ptr_base<T, D> &x,
+	    const detail::unique_ptr_base<U, E> &y)
+{ return !(x < y); }
+
+/* std::move "emulation".  This is as simple as it can be -- no
+   attempt is made to emulate rvalue references.  Instead relies on
+   the fact that gnu::unique_ptr has move semantics like
+   std::auto_ptr.  I.e., copy/assignment actually moves.  */
+
+template<typename T, typename D>
+unique_ptr<T, D>
+move (unique_ptr<T, D> v)
+{
+  return v;
+}
+
+#endif /* C++11 */
+
+/* Define gnu::unique_xmalloc_ptr, a gnu::unique_ptr that manages
+   xmalloc'ed memory.  */
+
+/* The deleter for gnu::unique_xmalloc_ptr.  Uses free.  */
+template <typename T>
+struct xmalloc_deleter
+{
+  void operator() (T *ptr) const { free (ptr); }
+};
+
+/* Same, for arrays.  */
+template <typename T>
+struct xmalloc_deleter<T[]>
+{
+  void operator() (T *ptr) const { free (ptr); }
+};
+
+#if __cplusplus >= 201103
+
+/* In C++11, we just import the standard unique_ptr to our namespace
+   with a custom deleter.  */
+
+template<typename T> using unique_xmalloc_ptr
+  = std::unique_ptr<T, xmalloc_deleter<T>>;
+
+#else /* C++11 */
+
+/* In C++03, we don't have template aliases, so we need to define a
+   subclass instead, and re-define the constructors, because C++03
+   doesn't support inheriting constructors either.  */
+
+template <typename T>
+class unique_xmalloc_ptr : public unique_ptr<T, xmalloc_deleter<T> >
+{
+  typedef unique_ptr<T, xmalloc_deleter<T> > base_type;
+
+  DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
+};
+
+/* Define gnu::unique_xmalloc_ptr specialization for T[].  */
+
+template <typename T>
+class unique_xmalloc_ptr<T[]> : public unique_ptr<T[], xmalloc_deleter<T[]> >
+{
+  typedef unique_ptr<T[], xmalloc_deleter<T[]> > base_type;
+
+  DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
+};
+
+#endif /* C++11 */
+
+} /* namespace gnu */
+
+#endif /* GNU_UNIQUE_PTR_H */