/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_UNIQUE_PTR_H #define EASTL_UNIQUE_PTR_H #include #include #include // Defines smart_ptr_deleter #include // Defines EASTL_MOVE #include #include #include #include #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. #endif namespace eastl { /// class unique_ptr /// /// This class implements a unique_ptr template. This is a class which is /// similar to the C++ auto_ptr template, except that it prohibits copying /// of itself, for safety. /// /// More specifically, the unique_ptr class template stores a pointer to a /// dynamically allocated object. The object pointed to is automatically /// deleted on destructor of unique_ptr or can be manually deleted via the /// unique_ptr::reset function. /// /// Memory allocation notes: /// unique_ptr doesn't allocate memory; all allocated pointers are externally /// derived. unique_ptr does deallocate memory, though always through the /// user-provided deleter. You need to make sure you are consistent in providing /// a deleter which frees memory in a way that matches how it was originally allocated. /// Deleters have instance information and are moved between containers the same way /// the allocated pointers are. Thus you can allocate memory via some heap and /// provide a deleter which contains a pointer to that same heap, and regardless /// of what you do with the unique_ptr, including moving it to another unique_ptr, /// the deletion will use the originally provided heap. /// /// Example usage: /// unique_ptr p(new int); /// *p = 4; /// /// unique_ptr pArray(new int[4]); /// p[0] = 4; /// /// Type completeness requirements /// http://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t/6089065#6089065 /// Here is a table which documents several members of shared_ptr and unique_ptr with respect to completeness requirements. /// If the member requires a complete type, the entry has a "C", otherwise the table entry is filled with "I". /// /// unique_ptr shared_ptr /// +------------------------+---------------+---------------+ /// | P() | I | I | /// | default constructor | | | /// +------------------------+---------------+---------------+ /// | P(const P&) | N/A | I | /// | copy constructor | | | /// +------------------------+---------------+---------------+ /// | P(P&&) | I | I | /// | move constructor | | | /// +------------------------+---------------+---------------+ /// | ~P() | C | I | /// | destructor | | | /// +------------------------+---------------+---------------+ /// | P(A*) | I | C | /// +------------------------+---------------+---------------+ /// | operator=(const P&) | N/A | I | /// | copy assignment | | | /// +------------------------+---------------+---------------+ /// | operator=(P&&) | C | I | /// | move assignment | | | /// +------------------------+---------------+---------------+ /// | reset() | C | I | /// +------------------------+---------------+---------------+ /// | reset(A*) | C | C | /// +------------------------+---------------+---------------+ /// template > class unique_ptr { public: typedef Deleter deleter_type; typedef T element_type; typedef unique_ptr this_type; typedef typename Internal::unique_pointer_type::type pointer; public: /// unique_ptr /// Construct a unique_ptr from a pointer allocated via new. /// Example usage: /// unique_ptr ptr; EA_CPP14_CONSTEXPR unique_ptr() EA_NOEXCEPT : mPair(pointer()) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } /// unique_ptr /// Construct a unique_ptr from a null pointer. /// Example usage: /// unique_ptr ptr(nullptr); EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EA_NOEXCEPT : mPair(pointer()) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } /// unique_ptr /// Construct a unique_ptr from a pointer allocated via new. /// Example usage: /// unique_ptr ptr(new int(3)); explicit unique_ptr(pointer pValue) EA_NOEXCEPT : mPair(pValue) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } /// unique_ptr /// Constructs a unique_ptr with the owner pointer and deleter specified /// Example usage: /// eastl::smart_ptr_deleter del; /// unique_ptr ptr(new int(3), del); unique_ptr(pointer pValue, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter) EA_NOEXCEPT : mPair(pValue, deleter) {} /// unique_ptr /// Constructs a unique_ptr with the owned pointer and deleter specified (rvalue) /// Example usage: /// unique_ptr ptr(new int(3), eastl::smart_ptr_deleter()); unique_ptr(pointer pValue, typename eastl::remove_reference::type&& deleter) EA_NOEXCEPT : mPair(pValue, eastl::move(deleter)) { static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } /// unique_ptr /// Move constructor /// Example usage: /// unique_ptr ptr(new int(3)); /// unique_ptr newPtr = eastl::move(ptr); unique_ptr(this_type&& x) EA_NOEXCEPT : mPair(x.release(), eastl::forward(x.get_deleter())) {} /// unique_ptr /// Move constructor /// Example usage: /// unique_ptr ptr(new int(3)); /// unique_ptr newPtr = eastl::move(ptr); template unique_ptr(unique_ptr&& u, typename enable_if::value && is_convertible::pointer, pointer>::value && is_convertible::value && (is_same::value || !is_reference::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} /// unique_ptr /// Move assignment /// Example usage: /// unique_ptr ptr(new int(3)); /// unique_ptr newPtr(new int(4)); /// ptr = eastl::move(newPtr); // Deletes int(3) and assigns mpValue to int(4) this_type& operator=(this_type&& x) EA_NOEXCEPT { reset(x.release()); mPair.second() = eastl::move(eastl::forward(x.get_deleter())); return *this; } /// unique_ptr /// Move assignment template typename enable_if::value && is_convertible::pointer, pointer>::value && is_assignable::value, this_type&>::type operator=(unique_ptr&& u) EA_NOEXCEPT { reset(u.release()); mPair.second() = eastl::move(eastl::forward(u.get_deleter())); return *this; } /// operator=(nullptr_t) this_type& operator=(std::nullptr_t) EA_NOEXCEPT { reset(); return *this; } /// ~unique_ptr /// Destroys the owned pointer. The destructor for the object /// referred to by the owned pointer will be called. ~unique_ptr() EA_NOEXCEPT { reset(); } /// reset /// Deletes the owned pointer and takes ownership of the /// passed in pointer. If the passed in pointer is the same /// as the owned pointer, nothing is done. /// Example usage: /// unique_ptr ptr(new int(3)); /// ptr.reset(new int(4)); // deletes int(3) /// ptr.reset(NULL); // deletes int(4) void reset(pointer pValue = pointer()) EA_NOEXCEPT { if (pValue != mPair.first()) { if (mPair.first()) get_deleter()(mPair.first()); mPair.first() = pValue; } } /// release /// This simply forgets the owned pointer. It doesn't /// free it but rather assumes that the user does. /// Example usage: /// unique_ptr ptr(new int(3)); /// int* pInt = ptr.release(); /// delete pInt; pointer release() EA_NOEXCEPT { pointer const pTemp = mPair.first(); mPair.first() = pointer(); return pTemp; } /// detach /// For backwards-compatibility with pre-C++11 code. pointer detach() EA_NOEXCEPT { return release(); } /// swap /// Exchanges the owned pointer beween two unique_ptr objects. void swap(this_type& x) EA_NOEXCEPT { mPair.swap(x.mPair); } /// operator* /// Returns the owner pointer dereferenced. /// Example usage: /// unique_ptr ptr(new int(3)); /// int x = *ptr; typename add_lvalue_reference::type operator*() const // Not noexcept, because the pointer may be NULL. { return *mPair.first(); } /// operator-> /// Allows access to the owned pointer via operator->() /// Example usage: /// struct X{ void DoSomething(); }; /// unique_ptr ptr(new X); /// ptr->DoSomething(); pointer operator->() const EA_NOEXCEPT { return mPair.first(); } /// get /// Returns the owned pointer. Note that this class does /// not provide an operator T() function. This is because such /// a thing (automatic conversion) is deemed unsafe. /// Example usage: /// struct X{ void DoSomething(); }; /// unique_ptr ptr(new X); /// X* pX = ptr.get(); /// pX->DoSomething(); pointer get() const EA_NOEXCEPT { return mPair.first(); } /// get_deleter /// Returns the deleter used to delete the owned pointer /// Example usage: /// unique_ptr ptr(new int(3)); /// eastl::smart_ptr_deleter& del = ptr.get_deleter(); deleter_type& get_deleter() EA_NOEXCEPT { return mPair.second(); } /// get_deleter /// Const version for getting the deleter const deleter_type& get_deleter() const EA_NOEXCEPT { return mPair.second(); } #ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS /// Note that below we do not use operator bool(). The reason for this /// is that booleans automatically convert up to short, int, float, etc. /// The result is that this: if(uniquePtr == 1) would yield true (bad). typedef T* (this_type::*bool_)() const; operator bool_() const EA_NOEXCEPT { if(mPair.first()) return &this_type::get; return NULL; } bool operator!() const EA_NOEXCEPT { return (mPair.first() == pointer()); } #else /// operator bool /// Allows for using a unique_ptr as a boolean. /// Example usage: /// unique_ptr ptr(new int(3)); /// if(ptr) /// ++*ptr; /// explicit operator bool() const EA_NOEXCEPT { return (mPair.first() != pointer()); } #endif /// These functions are deleted in order to prevent copying, for safety. unique_ptr(const this_type&) = delete; unique_ptr& operator=(const this_type&) = delete; unique_ptr& operator=(pointer pValue) = delete; protected: eastl::compressed_pair mPair; }; // class unique_ptr /// unique_ptr specialization for unbounded arrays. /// /// Differences from unique_ptr: /// - Conversions between different types of unique_ptr or to or /// from the non-array forms of unique_ptr produce an ill-formed program. /// - Pointers to types derived from T are rejected by the constructors, and by reset. /// - The observers operator* and operator-> are not provided. /// - The indexing observer operator[] is provided. /// - The default deleter will call delete[]. /// /// It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]). /// /// Example usage: /// unique_ptr ptr(new int[10]); /// ptr[4] = 4; /// template class unique_ptr { public: typedef Deleter deleter_type; typedef T element_type; typedef unique_ptr this_type; typedef typename Internal::unique_pointer_type::type pointer; public: EA_CPP14_CONSTEXPR unique_ptr() EA_NOEXCEPT : mPair(pointer()) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } EA_CPP14_CONSTEXPR unique_ptr(std::nullptr_t) EA_NOEXCEPT : mPair(pointer()) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } template // Pointers to types derived from T are rejected by the constructors, and by reset. explicit unique_ptr(P pArray, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT : mPair(pArray) { static_assert(!eastl::is_pointer::value, "unique_ptr deleter default-constructed with null pointer. Use a different constructor or change your deleter to a class."); } template unique_ptr(P pArray, typename eastl::conditional::value, deleter_type, typename eastl::add_lvalue_reference::type>::type deleter, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT : mPair(pArray, deleter) {} template unique_ptr(P pArray, typename eastl::remove_reference::type&& deleter, typename eastl::enable_if::value>::type* = 0) EA_NOEXCEPT : mPair(pArray, eastl::move(deleter)) { static_assert(!eastl::is_reference::value, "deleter_type reference refers to an rvalue deleter. The reference will probably become invalid before used. Change the deleter_type to not be a reference or construct with permanent deleter."); } unique_ptr(this_type&& x) EA_NOEXCEPT : mPair(x.release(), eastl::forward(x.get_deleter())) {} template unique_ptr(unique_ptr&& u, typename enable_if::pointer>::value && eastl::is_convertible::value && (!eastl::is_reference::value || eastl::is_same::value)>::type* = 0) EA_NOEXCEPT : mPair(u.release(), eastl::forward(u.get_deleter())) {} this_type& operator=(this_type&& x) EA_NOEXCEPT { reset(x.release()); mPair.second() = eastl::move(eastl::forward(x.get_deleter())); return *this; } template typename enable_if::pointer>::value && is_assignable::value, this_type&>::type operator=(unique_ptr&& u) EA_NOEXCEPT { reset(u.release()); mPair.second() = eastl::move(eastl::forward(u.get_deleter())); return *this; } this_type& operator=(std::nullptr_t) EA_NOEXCEPT { reset(); return *this; } ~unique_ptr() EA_NOEXCEPT { reset(); } void reset(pointer pArray = pointer()) EA_NOEXCEPT { if(pArray != mPair.first()) { get_deleter()(mPair.first()); mPair.first() = pArray; } } pointer release() EA_NOEXCEPT { pointer const pTemp = mPair.first(); mPair.first() = pointer(); return pTemp; } /// detach /// For backwards-compatibility with pre-C++11 code. pointer detach() EA_NOEXCEPT { return release(); } void swap(this_type& x) EA_NOEXCEPT { mPair.swap(x.mPair); } /// operator[] /// Returns a reference to the specified item in the owned pointer /// array. /// Example usage: /// unique_ptr ptr(new int[6]); /// int x = ptr[2]; typename add_lvalue_reference::type operator[](ptrdiff_t i) const { // assert(mpArray && (i >= 0)); return mPair.first()[i]; } pointer get() const EA_NOEXCEPT { return mPair.first(); } deleter_type& get_deleter() EA_NOEXCEPT { return mPair.second(); } const deleter_type& get_deleter() const EA_NOEXCEPT { return mPair.second(); } #ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS typedef T* (this_type::*bool_)() const; operator bool_() const EA_NOEXCEPT { if(mPair.first()) return &this_type::get; return NULL; } bool operator!() const EA_NOEXCEPT { return (mPair.first() == pointer()); } #else explicit operator bool() const EA_NOEXCEPT { return (mPair.first() != pointer()); } #endif /// These functions are deleted in order to prevent copying, for safety. unique_ptr(const this_type&) = delete; unique_ptr& operator=(const this_type&) = delete; unique_ptr& operator=(pointer pArray) = delete; protected: eastl::compressed_pair mPair; }; /// make_unique /// /// The C++11 Standard doesn't have make_unique, but there's no agreed reason as to why. /// http://stackoverflow.com/questions/12580432/why-does-c11-have-make-shared-but-not-make-unique /// http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/ /// Herb's solution is OK but doesn't support unique_ptr<[]> (array version). We do the same /// thing libc++ does and make a specialization of make_unique for arrays. /// /// make_unique has two cases where you can't use it and need to directly use unique_ptr: /// - You need to construct the unique_ptr with a raw pointer. /// - You need to specify a custom deleter. /// /// Note: This function uses global new T by default to create the ptr instance, as per /// the C++11 Standard make_shared_ptr. /// /// Example usage: /// struct Test{ Test(int, int){} }; /// auto p = make_unique(1, 2); /// /// auto pArray = make_unique(4); /// namespace Internal { template struct unique_type { typedef unique_ptr unique_type_single; }; template struct unique_type { typedef unique_ptr unique_type_unbounded_array; }; template struct unique_type { typedef void unique_type_bounded_array; }; } template inline typename Internal::unique_type::unique_type_single make_unique(Args&&... args) { return unique_ptr(new T(eastl::forward(args)...)); } template inline typename Internal::unique_type::unique_type_unbounded_array make_unique(size_t n) { typedef typename eastl::remove_extent::type TBase; return unique_ptr(new TBase[n]); } // It's not possible to create a unique_ptr for arrays of a known bound (e.g. int[4] as opposed to int[]). template typename Internal::unique_type::unique_type_bounded_array make_unique(Args&&...) = delete; /// hash specialization for unique_ptr. /// It simply returns eastl::hash(x.get()). If your unique_ptr pointer type (the return value of unique_ptr::get) is /// a custom type and not a built-in pointer type then you will need to independently define eastl::hash for that type. template struct hash< unique_ptr > { size_t operator()(const unique_ptr& x) const EA_NOEXCEPT { return eastl::hash::pointer>()(x.get()); } }; /// swap /// Exchanges the owned pointer beween two unique_ptr objects. /// This non-member version is useful for compatibility of unique_ptr /// objects with the C++ Standard Library and other libraries. template inline void swap(unique_ptr& a, unique_ptr& b) EA_NOEXCEPT { a.swap(b); } template inline bool operator==(const unique_ptr& a, const unique_ptr& b) { return (a.get() == b.get()); } template inline bool operator!=(const unique_ptr& a, const unique_ptr& b) { return !(a.get() == b.get()); } /// Returns which unique_ptr is 'less' than the other. Useful when storing /// sorted containers of unique_ptr objects. template inline bool operator<(const unique_ptr& a, const unique_ptr& b) { //typedef typename eastl::unique_ptr::pointer P1; // We currently need to make these temporary variables, as otherwise clang complains about CPointer being int*&&&. //typedef typename eastl::unique_ptr::pointer P2; // I think there's something wrong with our common_type type trait implementation. //typedef typename eastl::common_type::type PCommon; // "in instantiation of function template specialization 'eastl::operator<, no known conversion from 'element_type *' (aka 'int *') to 'int *&&&' for 1st argument" //return less()(a.get(), b.get()); // It looks like common_type is making CPointer be (e.g.) int*&& instead of int*, though the problem may be in how less<> deals with that. typedef typename eastl::unique_ptr::pointer P1; typedef typename eastl::unique_ptr::pointer P2; typedef typename eastl::common_type::type PCommon; PCommon pT1 = a.get(); PCommon pT2 = b.get(); return less()(pT1, pT2); } template inline bool operator>(const unique_ptr& a, const unique_ptr& b) { return (b < a); } template inline bool operator<=(const unique_ptr& a, const unique_ptr& b) { return !(b < a); } template inline bool operator>=(const unique_ptr& a, const unique_ptr& b) { return !(a < b); } template inline bool operator==(const unique_ptr& a, std::nullptr_t) EA_NOEXCEPT { return !a; } template inline bool operator==(std::nullptr_t, const unique_ptr& a) EA_NOEXCEPT { return !a; } template inline bool operator!=(const unique_ptr& a, std::nullptr_t) EA_NOEXCEPT { return static_cast(a); } template inline bool operator!=(std::nullptr_t, const unique_ptr& a) EA_NOEXCEPT { return static_cast(a); } template inline bool operator<(const unique_ptr& a, std::nullptr_t) { typedef typename unique_ptr::pointer pointer; return less()(a.get(), nullptr); } template inline bool operator<(std::nullptr_t, const unique_ptr& b) { typedef typename unique_ptr::pointer pointer; pointer pT = b.get(); return less()(nullptr, pT); } template inline bool operator>(const unique_ptr& a, std::nullptr_t) { return (nullptr < a); } template inline bool operator>(std::nullptr_t, const unique_ptr& b) { return (b < nullptr); } template inline bool operator<=(const unique_ptr& a, std::nullptr_t) { return !(nullptr < a); } template inline bool operator<=(std::nullptr_t, const unique_ptr& b) { return !(b < nullptr); } template inline bool operator>=(const unique_ptr& a, std::nullptr_t) { return !(a < nullptr); } template inline bool operator>=(std::nullptr_t, const unique_ptr& b) { return !(nullptr < b); } } // namespace eastl #endif // Header include guard