/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03. Copyright (C) 2007-2020 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 #if __cplusplus >= 201103 # include #endif 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. This relies on T having move semantics like std::auto_ptr. I.e., copy/assignment actually moves. */ template const T& move (T& 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); } }; /* Same, for arrays. */ 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) }; /* Define gnu::unique_xmalloc_ptr specialization for T[]. */ 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 */