1. Acknowledgements
I’d like to thank the following:
- 
     Jackie Kay and Brittany Friedman for encouraging me to submit this proposal. 
- 
     Gor Nishanov, whose coroutine slides at CppCon 2016 gave me the final push to sit down and write this. 
- 
     Bryce "Wash" Lelbach for representing this paper when I was unable to. 
- 
     Mark Zeren for constantly bugging me to see if I might update this paper. 
- 
     JF Bastien and Billy O’Neal for assisting me with some atomic operations, which I am absolute garbage at. 
2. Revision History
2.1. Revision 1
- 
     Rewrote proposal in bikeshed, the hot new format that every cool proposal writer is using now. 
- 
     Clarified section on addressof operator, now that out_ptr 
- 
     Removed retain_ptr :: unique shared_ptr 
- 
     Removed code example of implementing a std :: future 
- 
     Changed retain_ptr :: detach retain_ptr :: release 
- 
     Changed name of retain_t retain_object_t 
- 
     Changed atomicity of atomic_reference_count 
- 
     Changed wording to use C++17/C++20 features. 
- 
     Changed order of document. §7 Technical Specification is now at the very end of the document, and §6 Examples are further up. 
- 
     Added adopt_object_t default_action 
- 
     Added static_pointer_cast dynamic_pointer_cast const_pointer_cast reinterpret_pointer_cast 
- 
     Added deduction guides to bring retain_ptr 
- 
     Added more code examples 
2.2. Revision 0
Initial Release 🎉
3. Motivation
There are a wide variety of C and C++ APIs that rely on reference counting,
but either because of the language (C) or the age of the library (C++), they
are unable to be safely use with either 
Those that work on systems or tools that rely on reference counting stand to
benefit most from 
If 
A reference implementation of 
4. Scope and Impact
5. Frequently Asked Questions
Several common questions regarding the design of 
5.1. How does intrusive_ptr 
   
Additionally, 
Furthermore, 
- 
     intrusive_add_ref 
- 
     intrusive_release 
While this approach is fine in most cases, it does remove the ability to easily "swap out" the actions taken when increment or decrementing the reference count (e.g., setting a debugger breakpoint on a specific traits implementation, but not on all traits implementations). This naming convention uses terms found in Microsoft’s COM. While this isn’t an issue per se, it would be odd to have functions with those names found in the standard.
5.2. Why is it called retain_ptr intrusive_ptr 
   
Some additional names that might be considered (for bikeshedding) are:
- 
     extend_ptr 
- 
     counted_ptr 
- 
     borrow_ptr 
- 
     mutual_ptr 
- 
     joint_ptr 
Comedy Option:
- 
     auto_ptr 
5.3. Is retain_ptr 
   
5.4. Does retain_ptr 
   
5.5. Can retain_ptr 
   Possibly. However, I question the usefulness for a constexpr capable intrusive
smart pointer, as most use cases are intended for non-constexpr capable
interfaces such as incomplete types and polymorphic classes. Additionally, 
5.6. Does retain_ptr 
   The default action that 
5.7. Why provide retain_object_t adopt_object_t 
   
Technically, an 
The names of these sentinels are available for bikeshedding. Some other
possible names for 
- 
     retain_element_t 
- 
     extend_element_t 
- 
     retainobj_t 
- 
     extendobj_t 
While 
- 
     borrow_object_t 
- 
     borrow_element_t 
- 
     borrowobj_t 
- 
     adopt_element_t 
- 
     adoptobj_t 
5.8. Does retain_ptr 
   Originally, this proposal suggested 
5.9. Can retain_traits 
   No. Any important state regarding the object or how it is retained, can be
stored in the object itself. For example, if the reference count needs to be
external from the object, 
5.10. Why not just wrap a unique_ptr 
   This is an extraordinary amount of code across many existing libraries that
would not be guaranteed to have a homogenous interface. For example, using 
struct context_traits { using pointer = cl_context ; static void increment ( pointer p ) { clRetainContext ( p ); } static void decrement ( pointer p ) { clReleaseContext ( p ); } }; struct context { using handle_type = retain_ptr < cl_context , context_traits > ; using pointer = handle_type :: pointer ; context ( pointer p , retain_object_t ) : handle ( p , retain ) { } context ( pointer p ) : handle ( p ) { } private : handle_type handle ; }; 
Using the 
struct context_deleter { using pointer = cl_context ; void increment ( pointer p ) const { if ( p ) { clRetainContext ( p ); } // retain_ptr checks for null for us } void operator () ( pointer p ) const { clReleaseContext ( p ); } }; struct retain_object_t { }; constexpr retain_object_t retain { }; struct context { using handle_type = unique_ptr < cl_context , context_deleter > ; using pointer = handle_type :: pointer ; context ( pointer p , retain_object_t ) : context ( p ) { handle . get_deleter (). increment ( handle . get ()); } context ( pointer p ) : handle ( p ) { } context ( context const & that ) : handle ( that . handle . get ()) { handle . get_deleter (). increment ( handle . get ()) } context & operator = ( context const & that ) { context ( that . handle . get (), retain ). swap ( * this ); return * this ; } void swap ( context & that ) noexcept { handle . swap ( that ); } private : handle_type handle ; }; 
As we can see, using 
6. Examples
Some C APIs that would benefit from 
- 
     OpenCL 
- 
     Mono (Assembly and Image types) 
- 
     CPython 
- 
     ObjC Runtime 
- 
     Grand Central Dispatch 
Inside the [implementation] repository is an extremely basic example of using 
6.1. OpenCL
As shown above, using 
struct context_traits { using pointer = cl_context ; static void increment ( pointer p ) { clRetainContext ( p ); } static void decrement ( pointer p ) { clReleaseContext ( p ); } }; struct context { using handle_type = retain_ptr < cl_context , context_traits > ; using pointer = handle_type :: pointer ; context ( pointer p , retain_object_t ) : handle ( p , retain ) { } context ( pointer p ) : handle ( p ) { } private : handle_type handle ; }; 
6.2. ObjC Runtime
Additionally, while some additional work is needed to interact with the rest of
the ObjC runtime, 
struct objc_traits { using pointer = CFTypeRef ; static void increment ( pointer p ) { CFRetain ( p ); } static void decrement ( pointer p ) { CFRelease ( p ); } }; 
6.3. DirectX and COM
Because DirectX is a COM interface, it can also benefit from the use of 
struct com_traits { static void increment ( IUnknown * ptr ) { ptr -> AddRef (); } static void decrement ( IUnknown * ptr ) { ptr -> Release (); } }; template < class T > using com_ptr = retain_ptr < T * , com_traits > ; struct GpuResource { friend class GraphicsContext ; friend class CommandContext ; friend class ComputeContext ; GpuResource ( ID3D12Resource * resource , D3D12_RESOURCE_STATES current ) : resource ( resource ), usage_state ( current ) { } GpuResource () = default ; ID3D12Resource * operator -> () noexcept { return this -> resource . get (); } ID3D12Resource const * operator -> () const noexcept { return this -> resource . get (); } protected : com_ptr < ID3D12Resource > resource { }; D3D12_RESOURCE_STATES usage_state = D3D12_RESOURCE_STATE_COMMON ; D3D12_RESOURCE_STATES transitioning_state = D3D_RESOURCE_STATES ( - 1 ); D3D12_GPU_VIRTUAL_ADDRESS virtual_address = D3D12_GPU_VIRTUAL_ADDRESS_NULL ; void * user_memory = nullptr ; }; 
6.4. WebKit’s RefPtr
As a small demonstration of replacing existing intrusive smart pointers with 
RefPtr < Node > node = adoptRef ( rawNodePointer ); 
auto node = retain_ptr < Node > ( rawNodePointer , adopt_object ); 
7. Technical Specification
A retain pointer is an object that extends the lifetime of another object
(which in turn manages its own dispostion) and manages that other object
through a pointer. Specifically, a retain pointer is an object r that stores
a pointer to a second object p and will cease to extend the lifetime of p when r is itself destroyed (e.g., when leaving a block scope). In this
context, r is said to retain 
When p's lifetime has reached its end, p will dispose of itself as it sees fit. The conditions regarding p's lifetime is handled by some count c that p comprehends, but is otherwise not directly accessible to r.
The mechanism by which r retains and manages the lifetime of p is known as p's associated retainer, a stateless object that provides mechanisms for r to increment, decrement, and (optionally) provide access to c. In this
context, r is able to increment 
Let the notation r.p denote the pointer stored by r. Upon request, r can explicitly choose to increment c when r.p is replaced.
Additionally, r can, upon request, transfer ownership to another retain pointer r2. Upon completion of such a transfer, the following postconditions hold:
- 
     r2.p is equal to the pre-transfer r.p, and 
- 
     r.p is equal to nullptr 
Furthermore, r can, upon request, extend ownership to another retain pointer r2. Upon completion of such an extension, the following postconditions hold:
- 
     r2.p is equal to r.p 
- 
     c has been incremented by 1 
Each object of a type 
class atomic_reference_count < T > ; class reference_count < T > ; class retain_object_t ; class adopt_object_t ; template < class T > struct retain_traits ; template < class T , class R = retain_traits < T >> class retain_ptr ; template < class T , class R > void swap ( retain_ptr < T , R >& x , retain_ptr < T , R >& y ) noexcept ; template < class T , class R , class U > retain_ptr < T , R > dynamic_pointer_cast ( retain_ptr < U , R > const & ) noexcept ; template < class T , class R , class U > retain_ptr < T , R > static_pointer_cast ( retain_ptr < U , R > const & ) noexcept ; template < class T , class R , class U > retain_ptr < T , R > const_pointer_cast ( retain_ptr < U , R > const & ) noexcept ; template < class T , class R , class U > retain_ptr < T , R > reinterpret_pointer_cast ( retain_ptr < U , R > const & ) noexcept ; template < class T , class R , class S = R > strong_ordering operator <=> ( retain_ptr < T , R > const & x , retain_ptr < T , S > const & y ) noexcept ; template < class T , class R > strong_ordering operator <=> ( retain_ptr < T , R > const & x , nullptr_t ) noexcept ; template < class T , class R > strong_ordering operator <=> ( nullptr_t , retain_ptr < T , R > const & y ) noexcept ; 
7.1. atomic_reference_count < T > reference_count < T > 
   
template < class T > struct atomic_reference_count { friend retain_traits < T > ; protected : atomic_reference_count () = default ; private : atomic < uint_least64_t > count { 1 }; // provided for exposition }; template < class T > struct reference_count { friend retain_traits < T > ; protected : reference_count () = default ; private : uint_least64_t count { 1 }; // provided for exposition }; 
7.2. retain_object_t adopt_object_t 
   
namespace std { struct retain_object_t { constexpr retain_object_t () = default ; }; struct adopt_object_t { constexpr adopt_object_t () = default ; }; constexpr retain_object_t retain_object { }; constexpr adopt_object_t adopt_object { }; } 
7.3. retain_traits < T > 
   The class template 
namespace std { template < class T > struct retain_traits { static void increment ( atomic_reference_count < T >* ) noexcept ; static void decrement ( atomic_reference_count < T >* ) noexcept ; static long use_count ( atomic_reference_count < T >* ) noexcept ; static void increment ( reference_count < T >* ) noexcept ; static void decrement ( reference_count < T >* ) noexcept ; static long use_count ( reference_count < T >* ) noexcept ; }; } 
static void increment ( atomic_reference_count < T >* ptr ) noexcept ; 
1 Effects: Increments the internal reference count for ptr withmemory_order :: relaxed 
2 Postcondition:has been incremented by 1.ptr -> count 
static void decrement ( atomic_reference_count < T >* ptr ) noexcept ; 
1 Effects: Decrements the internal reference count for ptr with. If the internal reference count of ptr reaches 0, it is disposed of viamemory_order :: acq_rel .delete 
static long use_count ( atomic_reference_count < T >* ptr ) noexcept ; 
1 Returns: The internal reference count for ptr with.memory_order :: acquire 
static void increment ( reference_count < T >* ptr ) noexcept ; 
1 Effects: Increments the internal reference count for ptr by 1.
static void decrement ( reference_count < T >* ptr ) noexcept ; 
1 Effects: Decrements the internal reference count for ptr by 1. If the count reaches 0, ptr is disposed of via.delete 
static long use_count ( reference_count < T >* ptr ) noexcept ; 
1 Returns: The reference count for ptr.
7.4. retain_ptr < T > 
   The default type for the template parameter 
If the qualified-id 
template < class T , class R = retain_traits < T >> struct retain_ptr { using element_type = T ; using traits_type = R ; using pointer = /* see below */ retain_ptr ( pointer , retain_object_t ); retain_ptr ( pointer , adopt_object_t ) noexcept ; explicit retain_ptr ( pointer ); retain_ptr ( nullptr_t ) noexcept ; retain_ptr ( retain_ptr const & ) noexcept ; retain_ptr ( retain_ptr && ) noexcept ; retain_ptr () noexcept ; ~ retain_ptr (); retain_ptr & operator = ( retain_ptr const & ); retain_ptr & operator = ( retain_ptr && ) noexcept ; retain_ptr & operator = ( nullptr_t ) noexcept ; void swap ( retain_ptr & ) noexcept ; explicit operator pointer () const noexcept ; explicit operator bool () const noexcept ; element_type & operator * () const noexcept ; pointer operator -> () const noexcept ; pointer get () const noexcept ; long use_count () const ; [[ nodiscard ]] pointer release () noexcept ; void reset ( pointer , retain_object_t ); void reset ( pointer , adopt_object_t ); void reset ( pointer p = pointer { }); }; 
7.4.1. retain_ptr 
   retain_ptr ( pointer p , retain_object_t ); 
Effects: Constructs a 
Postconditions: 
Remarks: If an exception is thrown during increment, this constructor will have no effect.
retain_ptr ( pointer p , adopt_object_t ) noexcept ; 
Effects: Constructs a 
Postconditions: 
Remarks: 
explicit retain_ptr ( pointer p ); 
Effects: Constructs a 
Postconditions: 
Remarks: If an exception is thrown, this constructor will have no effect.
retain_ptr () noexcept ; 
Effects: Constructs a 
Postconditions: 
retain_ptr ( retain_ptr const & r ); 
Effects: Constructs a 
Postconditions: 
Remarks: If an exception is thrown, this constructor will have no effect.
retain_ptr ( retain_ptr && r ) noexcept ; 
Effects: Constructs a 
Postconditions: 
7.4.2. retain_ptr 
   ~ retain_ptr (); 
Effects: If 
7.4.3. retain_ptr 
   retain_ptr & operator = ( retain_ptr const & r ); 
Effects: Extends ownership from 
retain_ptr & operator = ( retain_ptr && r ) noexcept ; 
Effects: Transfers ownership from 
retain_ptr & operator = ( nullptr_t ) noexcept ; 
Effects: 
7.4.4. retain_ptr 
   element_type & operator * () const noexcept ; 
Requires: 
pointer operator -> () const noexcept ; 
Requires: 
pointer get () const noexcept ; 
Returns: The stored pointer
explicit operator pointer () const noexcept ; 
Returns: 
explicit operator bool () const noexcept ; 
Returns: 
long use_count () const ; 
Returns: Value representing the current reference count of the current stored
pointer. If 
Remarks: Unless otherwise specified, the value returned should be considered stale.
7.4.5. retain_ptr 
   [[ nodiscard ]] pointer release () noexcept ; 
Postconditions: 
void reset ( pointer p , retain_object_t ); 
Effects: Assigns 
void reset ( pointer p , adopt_object_t ); 
Effects: Assigns 
void reset ( pointer p = pointer { }) 
Effects: Delegates assignment of 
void swap ( retain_ptr & r ) noexcept ; 
Effects: Invokes 
7.4.6. retain_ptr 
   template < class T , class R > void swap ( retain_ptr < T , R >& x , retain_ptr < T , R >& y ) noexcept ; 
Effects: Calls 
template < class T , class R > auto operator <=> ( retain_ptr < T , R > const & , retain_ptr < T , R > const & ) noexcept = default ; 
Returns: 
template < class T , class R > auto operator <=> ( retain_ptr < T , R > const & , nullptr_t ) noexcept = default ; 
Returns: 
template < class T , class R > strong_ordering operator <=> ( nullptr_t , retain_ptr < T , R > const & y ) noexcept ; 
Returns: