From patchwork Fri Oct 13 00:40:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 825176 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-464094-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="bgYnKmU1"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yCpm65QBHz9sNw for ; Fri, 13 Oct 2017 11:40:37 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=UZLKAjIHkvi25gev9yGCUFiil0zwZiq7t9M+ii5+PfLTOq55NwHMh A8L9xlUfvnKiw2y3o3X8Ii9ZnpjI2euBM/PY/5CgF/BMeOgSOEP5vFfyQzu7yKOp 1mGXWUMeX/dZJmt334yiQfMVv/MU4E2TJTV/n1bECaWPaYnOsyufEE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=vOeZumSFNnXPDO8COeCdTD4x8Bo=; b=bgYnKmU1dCBk1C6KXcHA hNOE3GZU/e0/pMZhJhwj1g0kfvA0MHHnkVyjejA0J+I8KP7XY49npaPDjO1rtWNl RlM/BflzErDl63dqB6AwjeXpYpXidloQJGATG7pPsXTIohf8IANCuZskGCGzg/o8 +po/tg8y2SS60ol1bSNZUyU= Received: (qmail 116511 invoked by alias); 13 Oct 2017 00:40:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 116502 invoked by uid 89); 13 Oct 2017 00:40:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=shoot, rvo, inheriting, overloaded X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 13 Oct 2017 00:40:24 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 21C1C4E33A; Fri, 13 Oct 2017 00:40:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 21C1C4E33A Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-12.phx2.redhat.com [10.3.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9091460632; Fri, 13 Oct 2017 00:40:21 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: Trevor Saunders , Jonathan Wakely , Richard Biener , Pedro Alves Subject: [PATCH] Add gnu::unique_ptr Date: Thu, 12 Oct 2017 20:40:53 -0400 Message-Id: <1507855253-47093-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <20171012140224.66nvonq7v5ii4jwh@ball> References: <20171012140224.66nvonq7v5ii4jwh@ball> X-IsSubscribed: yes From: Trevor Saunders I had a go at updating Trevor's unique_ptr patch from July ( https://gcc.gnu.org/ml/gcc-patches/2017-07/msg02084.html ) One of the sticking points was what to call the namespace; there was wariness about using "gtl" as the name. Richi proposed (https://gcc.gnu.org/ml/gcc-patches/2017-09/msg00155.html): > If it should be short use g::. We can also use gnu:: I guess and I > agree gnutools:: is a little long (similar to libiberty::). Maybe > gt:: as a short-hand for gnutools. Pedro noted (https://gcc.gnu.org/ml/gcc-patches/2017-09/msg00157.html): > Exactly 3 letters has the nice property of making s/gtl::foo/std::foo/ > super trivial down the road; you don't have to care about reindenting > stuff Hence this version of the patch uses "gnu::" - 3 letters, one of the ones Richi proposed, and *not* a match for ".tl" (e.g. "gtl"); (FWIW personally "gnu::" is my favorite, followed by "gcc::"). The include/unique-ptr.h in this patch is identical to that posted by Trevor in July, with the following changes (by me): - renaming of "gtl" to "gnu" - 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) I also went and added a gcc/unique-ptr-tests.cc file containing selftests (my thinking here is that although std::unique_ptr ought to already be well-tested, we need to ensure that the fallback implementation is sane when building with C++ prior to C++11). Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, using gcc 4.8 for the initial bootstrap (hence testing both gnu+03 and then gnu++14 in the selftests, for stage 1 and stages 2 and 3 respectively). I also manually tested selftests with both gcc 4.8 and trunk on the same hardware (again, to exercise both the with/without C++11 behavior). Tested with "make selftest-valgrind" (no new issues). OK for trunk? Motivation/use-cases: (a) I have an updated version of the name_hint/deferred_diagnostic patch kit, which uses this (rather than the refcounting used by https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00439.html ); and (b) having this available ought to allow various other cleanups e.g. the example ones identified by Trevor here: https://gcc.gnu.org/ml/gcc-patches/2017-07/msg02085.html Thanks Dave Blurb from Trevor: 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 include/ChangeLog: 2017-07-29 Trevor Saunders * unique-ptr.h: New file. Combined ChangeLog follows: gcc/ChangeLog: David Malcolm * 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 David Malcolm * unique-ptr.h: New file. --- gcc/Makefile.in | 1 + gcc/selftest-run-tests.c | 1 + gcc/selftest.h | 1 + gcc/unique-ptr-tests.cc | 177 ++++++++++++++++++++++ include/unique-ptr.h | 386 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 566 insertions(+) create mode 100644 gcc/unique-ptr-tests.cc create mode 100644 include/unique-ptr.h 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..df18467 --- /dev/null +++ b/gcc/unique-ptr-tests.cc @@ -0,0 +1,177 @@ +/* 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 +. */ + +#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; +}; + +} // anonymous namespace + +/* Verify that the default ctor inits ptrs to NULL. */ + +static void +test_null_ptr () +{ + gnu::unique_ptr p; + ASSERT_EQ (NULL, p); + + gnu::unique_xmalloc_ptr 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 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 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 (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 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 (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 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 g (new foo (s)); + ASSERT_NE (f, g); +} + +/* 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 (); +} + +} // namespace selftest + +#endif /* #if CHECKING_P */ diff --git a/include/unique-ptr.h b/include/unique-ptr.h new file mode 100644 index 0000000..eddb001 --- /dev/null +++ b/include/unique-ptr.h @@ -0,0 +1,386 @@ +/* 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 . */ + +/* 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 + +namespace gnu +{ + +#if __cplusplus >= 201103 + +/* In C++11 mode, all we need is import the standard + std::unique_ptr. */ +template using unique_ptr = std::unique_ptr; + +/* 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 +struct default_delete +{ + void operator () (T *ptr) const { delete ptr; } +}; + +/* Specialization for arrays. Uses delete[]. */ + +template +struct default_delete +{ + void operator () (T *ptr) const { delete [] ptr; } +}; + +namespace detail +{ +/* Type used to support implicit construction from NULL: + + gnu::unique_ptr func (....) + { + return NULL; + } + + and assignment from NULL: + + gnu::unique_ptr 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 and unique_ptr. */ + +template +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 (other).release ()) {} + + /* Converting "move" constructor. Really an lvalue ref converting + constructor that actually moves. This allows constructs such as: + + unique_ptr func_returning_unique_ptr (.....); + ... + unique_ptr ptr = func_returning_unique_ptr (.....); + */ + template + unique_ptr_base (const unique_ptr_base &other) throw () + : m_ptr (const_cast &> (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 (other).release ()); + return *this; + } + + /* Converting "move" assignment. Really an lvalue ref converting + copy assignment operator that moves. See comments above. */ + template + unique_ptr_base &operator= (const unique_ptr_base &other) throw () + { + reset (const_cast &> (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 \ + TYPE (const detail::unique_ptr_base &other) throw () \ + : base_type (other) {} \ + \ + using base_type::operator=; + +/* Define single-object gnu::unique_ptr. */ + +template > +class unique_ptr : public detail::unique_ptr_base +{ + typedef detail::unique_ptr_base 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 +class unique_ptr : public detail::unique_ptr_base +{ + typedef detail::unique_ptr_base base_type; + + DEFINE_GNU_UNIQUE_PTR (unique_ptr) + +public: + /* Indexing operator. */ + T &operator[] (size_t i) const { return this->get ()[i]; } +}; + +/* Comparison operators. */ + +template +inline bool +operator== (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &y) +{ return x.get() == y.get(); } + +template +inline bool +operator!= (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &y) +{ return x.get() != y.get(); } + +template +inline bool +operator< (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &y) +{ return x.get() < y.get (); } + +template +inline bool +operator<= (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &y) +{ return !(y < x); } + +template +inline bool +operator> (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &y) +{ return y < x; } + +template +inline bool +operator>= (const detail::unique_ptr_base &x, + const detail::unique_ptr_base &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 +unique_ptr +move (unique_ptr 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 +struct xmalloc_deleter +{ + 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 using unique_xmalloc_ptr + = std::unique_ptr>; + +#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 +class unique_xmalloc_ptr : public unique_ptr > +{ + typedef unique_ptr > base_type; + + DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr) +}; + +#endif /* C++11 */ + +} /* namespace gnu */ + +#endif /* GNU_UNIQUE_PTR_H */