A Proposal for the World s Dumbest Smart Pointer, v2

Similar documents
A Proposal for the World s Dumbest Smart Pointer

A polymorphic value-type for C++

A polymorphic value-type for C++

Constraining unique_ptr

Proposed Wording for Concurrent Data Structures: Hazard Pointer and Read Copy Update (RCU)

Splicing Maps and Sets (Revision 1)

A Proposal to Add a Const-Propagating Wrapper to the Standard Library

Apply the following edits to N4741, the working draft of the Standard. The feature test macros cpp_lib_latch and cpp_lib_barrier should be created.

A polymorphic value type for C++

Variant: a type-safe union without undefined behavior (v2).

memory_resource_ptr: A Limited Smart Pointer for memory_resource Correctness

Variant: a typesafe union. ISO/IEC JTC1 SC22 WG21 N4218

Revised Latches and Barriers for C++20

A jthread automatically signals an interrupt at the end of its lifetime to the started thread (if still joinable) and joins:

common_type and duration

Concepts for the C++0x Standard Library: Iterators (Revision 2)

Iterator Concepts for the C++0x Standard Library

Proposing Standard Library Support for the C++ Detection Idiom, v2

A Proposal to Add a Logical Const Wrapper to the Standard Library Technical Report

A Cooperatively Interruptible Joining Thread, Rev 4 New in R4

Generalized pointer casts

Concepts for the C++0x Standard Library: Iterators

Extending static_assert

Transformation Trait remove_cvref 1

G52CPP C++ Programming Lecture 20

C++11 and Compiler Update

Doc. No.: WG21/N0937=X3J16/ Date: 28 May 1996 Project: C++ Standard Library Reply to: Nathan Myers

Efficient concurrent waiting for C++20

A Unit Type for C++ Introduction. Related proposals. Proposed changes

Qualified std::function signatures

Object-Oriented Programming for Scientific Computing

Document Number: P0429R4 Date: Reply to: 0.1 Revisions... 1

Introduction to C++11 and its use inside Qt

CS 251 INTERMEDIATE SOFTWARE DESIGN SPRING C ++ Basics Review part 2 Auto pointer, templates, STL algorithms

1/29/2011 AUTO POINTER (AUTO_PTR) INTERMEDIATE SOFTWARE DESIGN SPRING delete ptr might not happen memory leak!

Pointers. Developed By Ms. K.M.Sanghavi

Proposed Wording for Concurrent Data Structures: Hazard Pointer and Read Copy Update (RCU)

September 10,

Absolute C++ Walter Savitch

C++11: 10 Features You Should be Using. Gordon R&D Runtime Engineer Codeplay Software Ltd.

Bring Back the Obvious Definition of count()

p0448r1 - A strstream replacement using span<chart> as buffer

Toward a Proposal for Object Templates in C++0x

Fixing Atomic Initialization, Rev1

Iterator Facade. Table of Contents. Overview. Usage. Iterator Core Access operator[] operator-> Reference

Instantiation of Template class

Smart Pointers. Some slides from Internet

CSE 333 Lecture smart pointers

Efficient waiting for concurrent programs

Template for comments and secretariat observations Date: Document: SC22 WG21 N4616 Project: 19568

Explicit Conversion Operator Draft Working Paper

Variant: a type-safe union that is rarely invalid (v5).

Responses to National Body Comments for ISO/IEC PDTS 19750, C++ Extensions for Parallelism Version 2

C++11/14 Rocks. Clang Edition. Alex Korban

American National Standards Institute Reply to: Josee Lajoie

A Standard flat_map. 1 Revisions. 2 Introduction. 3 Motivation and Scope. 1.1 Changes from R Changes from R0

Proposed Wording for Concurrent Data Structures: Read-Copy-Update (RCU)

CSE 333 Lecture smart pointers

04-17 Discussion Notes

std::optional from Scratch

Interrupt Tokens and a Joining Thread, Rev 7 New in R7

Type Erasure. Nevin :-) Liber Friday, October 29, Chicago C/C++ Users Group Nevin J. Liber All Rights Reserved.

A Standard flat_set. This paper outlines what a (mostly) API-compatible, non-node-based set might look like.

Botet C++ generic overload functions P0051

Working Draft, Extensions to C++ for Modules

Range Adaptors and Utilities

Hazard Pointers. Safe Resource Reclamation for Optimistic Concurrency

C++ Programming Lecture 7 Software Engineering Group

Improving the Return Value of Erase-Like Algorithms

Problem Solving with C++

Let return Be Direct and explicit

C The new standard

Source-Code Information Capture

Operator Dot Wording

Adding std::*_semaphore to the atomics clause.

Layout-compatibility and Pointer-interconvertibility Traits

Atomic maximum/minimum

Controlling Thread Stack Size at Creation Time

Short Notes of CS201

async and ~future (Revision 3)

Proposed Resolution to TR1 Issues 3.12, 3.14, and 3.15

Modern C++ for Computer Vision and Image Processing. Igor Bogoslavskyi

CS201 - Introduction to Programming Glossary By

Outline. 1 Function calls and parameter passing. 2 Pointers, arrays, and references. 5 Declarations, scope, and lifetimes 6 I/O

C++ Stability, Velocity, and Deployment Plans [R0]

More Improvements to std::future<t> - Revision 1

CS

Pairing off iterators

RAII and Smart Pointers. Ali Malik

Improving improved shared_ptr. 1.Overview. 2.Motivation. 3.Proposed text [util.smartptr.shared]

CSE 333 Lecture smart pointers

A Standard flat_map. Drop the requirement on container contiguity; sequence container will do.

Enhancing std::atomic_flag for waiting.

P0984R0 - All (*)()-Pointers Replaced by Ideal Lambdas Functions Objects Obsoleted by Lambdas

Midterm Review. PIC 10B Spring 2018

p0448r0 - A strstream replacement using span<chart> as

Rvalue References, Move Semantics, Universal References

COMP6771 Advanced C++ Programming

Exception Namespaces C Interoperability Templates. More C++ David Chisnall. March 17, 2011

A Generic Non-intrusive Smart Pointer Implementation

Transcription:

A Proposal for the World s Dumbest Smart Pointer, v2 Document #: WG21 N3740 Date: 2013-08-30 Revises: N3514 Project: JTC1.22.32 Programming Language C++ Reply to: Walter E. Brown <webrown.cpp@gmail.com> Contents 1 Introduction and motivation.... 1 2 Alternative approaches....... 2 3 A straw man implementation.... 3 4 Open questions............ 8 5 Proposed wording.......... 8 6 Acknowledgments.......... 14 7 Revision history............ 14 1 Introduction and motivation C++11 s shared_ptr and unique_ptr facilities, like C++98 s auto_ptr before them, provide considerable expressive power for handling memory resources. In addition to the technical benefits of such smart pointers, their names provide de facto vocabulary types 1 for describing certain common coding idioms that encompass pointer-related policies such as pointee copying and lifetime management. As another example, consider boost::optional, 2 which provides a pointer-like interface to access underlying (possibly uninitialized) values. Dave Abrahams characterizes 3 the fundamental semantics of optional [as] identical to those of a (non-polymorphic) clone_ptr. Thus optional provides vocabulary for another common coding idiom in which bare pointers have been historically used. Code that predates or otherwise avoids such smart pointers generally relies on C++ s native pointers for its memory management and allied needs, and so makes little or no coding use of any kind of standard descriptive vocabulary. As a result, it has often proven to be very challenging and time-consuming for a programmer to inspect code in order to discern the use to which any specific bare pointer is put, even if that use has no management role at all. As Loïc A. Joly observed, 4 it is not easy to disambiguate a T* pointer that is only observing the data.... Even if it would just 1 Defined by Pablo Halperin in N1850 as ubiquitous types used throughout the internal interfaces of a program. He goes on to say, The use of a well-defined set of vocabulary types... lends simplicity and clarity to a piece of code. 2 http://www.boost.org/doc/libs/1_52_0/libs/optional/doc/html/index.html. This functionality was recently accepted for C++14 per N3672 by Fernando Cacciola and Andrzej Krzemieński. See [optional]. 3 Reflector message c++std-lib-31692. 4 Reflector message c++std-lib-31595. 1

2 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 serve for documentation, having a dedicated type would have some value I think. Our experience leads us to agree with this assessment. 2 Alternative approaches Responding to Joly s above-cited comment, Howard Hinnant presented 5 the following (lightly reformatted, excerpted) C++11 code to demonstrate one candidate mechanism for achieving Joly s objective: 1 struct do_nothing 2 { 3 template <class T> 4 void operator ()(T*) { }; // do nothing 5 }; 7 template <class T> 8 using non_owning_ptr = unique_ptr<t, do_nothing>; At first glance, this certainly seems a reasonable approach. However, on further reflection, the copy semantics of these non_owning_ptr<> types seem subtly wrong for non-owning pointers (i.e., for pointers that behave strictly as observers): while the aliased underlying unique_ptr is (movable but) not copyable, we believe that an observer should be freely copyable to another observer object of the same or compatible type. Joly appears to concur with this view, stating 6 that non_owning_ptr should be CopyConstructible and Assignable. Later in the same thread, Howard Hinnant shared 7 his personal preference: I use raw pointers for non-owning relationships. And I actually *like* them. And I don t find them difficult or error prone. While this assessment from an acknowledged expert (with concurrence from others 8 ) is tempting, it seems most applicable when developing new code. However, we have found that a bare pointer is at such a low level of abstraction 9 that it can mean any one of quite a number of possibilities, especially when working with legacy code (e.g., when trying to divine its intent or trying to interoperate with it). Consistent with Bjarne Stroustrup s guideline 10 to avoid very general types in interfaces, our coding standard has for some time strongly discouraged the use of bare pointers in most public interfaces. 11 However, it seems clear that there is and will continue to be a role for non-owning, observe-only pointers. As Ville Voutilainen reminded us, 12 we haven t standardized every useful smart pointer yet. We certainly agree; in our experience, it has proven helpful to have a standard vocabulary type with which to document the observe-only behavior via code that can also interoperate with bare 5 Reflector message c++std-lib-31596. 6 Reflector message c++std-lib-31725. 7 Reflector message c++std-lib-31734. 8 For example, Nevin Liber in c++std-lib-31729 expresses a related preference: for non-owning situations use references where you can and pointers where you must..., and only use smart pointers when dealing with ownership. Other posters shared similar sentiments. 9 It has been said that bare pointers are to data structures as goto is to control structures. 10 See, for example, his keynote talk C++11 Style given 2012-02-02 during the GoingNative 2012 event held in Redmond, WA, USA. Video and slides at http://channel9.msdn.com/events/goingnative/goingnative-2012. 11 Constructor parameters are a notable exception. 12 Reflector message c++std-lib-31742.

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 3 pointers. The next section exhibits the essential aspects of exempt_ptr, our candidate for the (facetious yet descriptive) title of World s Dumbest Smart Pointer. 3 A straw man implementation We present the following code as a preliminary specification of intent in order to serve as a basis for technical discussion. Designed as a pointer that takes no formal notice of its pointee s lifetime, this not-very-smart pointer template is intended as a replacement for near-trivial uses of bare/native/raw/built-in/dumb C++ pointers, especially when used to communicate with (say) legacy code that traffics in such pointers. It is, by design, exempt (hence its working name) from any role in managing any pointee, and is thus freely copyable independent of and without regard for its pointee. We have found that such a template provides us a standard vocabulary to denote non-owning pointers, with no need for further comment or other documentation to describe the near-vacuous semantics involved. As a small bonus, this template s c tors ensure that all instance variables are initialized. 1 // ====================================================================== 2 // 3 // exempt_ptr: a pointer that is nearly oblivious to its pointee 4 // 5 // ====================================================================== 7 #include <cstddef> // nullptr_t, ptrdiff_t 8 #include <functional> // less 9 #include <iterator> // random_access_iterator_tag 10 #include <type_traits> // add_pointer, enable_if,... 11 #include <utility> // swap 13 // ----------------------------------------------- 14 // synopsis 16 template< class E > 17 class exempt_ptr; 19 template< class E > 20 void 21 swap( exempt_ptr<e> &, exempt_ptr<e> & ) noexcept; 23 template< class E > 24 exempt_ptr<e> 25 make_exempt( E * ) noexcept; 27 // (in)equality operators 28 template< class E1, class E2 > 29 bool 30 operator == ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 31 template< class E1, class E2 > 32 bool 33 operator!= ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 35 template< class E > 36 bool

4 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 37 operator == ( exempt_ptr<e> const &, nullptr_t ) noexcept; 38 template< class E > 39 bool 40 operator!= ( exempt_ptr<e> const &, nullptr_t ) noexcept; 42 template< class E > 43 bool 44 operator == ( nullptr_t, exempt_ptr<e> const & ) noexcept; 45 template< class E > 46 bool 47 operator!= ( nullptr_t, exempt_ptr<e> const & ) noexcept; 49 // ordering operators 50 template< class E1, class E2 > 51 bool 52 operator < ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 53 template< class E1, class E2 > 54 bool 55 operator > ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 56 template< class E1, class E2 > 57 bool 58 operator <= ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 59 template< class E1, class E2 > 60 bool 61 operator >= ( exempt_ptr<e1> const &, exempt_ptr<e2> const & ); 63 // arithmetic operators 64 template< class E > 65 exempt_ptr<e> 66 operator + ( ptrdiff_t, exempt_ptr<e> const & ); 67 template< class E > 68 ptrdiff_t 69 operator - ( exempt_ptr<e> const &, exempt_ptr<e> const & ); 71 // ----------------------------------------------- 72 // exempt_ptr 74 template< class E > 75 class exempt_ptr 76 { 77 public: 78 // publish our template parameter and variations thereof 79 using value_type = E; 80 using pointer = add_pointer_t<e>; 81 using const_pointer = add_pointer_t<e const>; 82 using reference = add_lvalue_reference_t<e>; 83 using const_reference = add_lvalue_reference_t<e const>; 85 // enable use as a pointer-like iterator 86 using difference_type = ptrdiff_t; 87 using iterator_category = random_access_iterator_tag; 89 private: 90 template< class P >

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 5 91 constexpr bool 92 is_compat( ) 93 { return is_convertible<add_pointer_t<p>, pointer>::value; } 95 public: 96 // default c tor 97 constexpr 98 exempt_ptr( ) noexcept : p{ nullptr } { } 100 // pointer-accepting c tors 101 constexpr 102 exempt_ptr( nullptr_t ) noexcept : exempt_ptr{} { } 103 explicit 104 exempt_ptr( pointer other ) noexcept : p{ other } { } 105 template< class E2 106, class = enable_if_t< is_compat<e2>() > 107 > 108 explicit 109 exempt_ptr( E2 * other ) noexcept : p{ other } { } 111 // copying c tors (in addition to compiler-generated copy c tor) 112 template< class E2 113, class = enable_if_t< is_compat<e2>() > 114 > 115 exempt_ptr( exempt_ptr<e2> const & other ) noexcept 116 : p{ other.get() } 117 { } 119 // pointer-accepting assignments 120 exempt_ptr & 121 operator = ( nullptr_t ) noexcept 122 { reset(nullptr); return *this; } 123 template< class E2 > 124 enable_if_t< is_compat<e2>(), exempt_ptr & > 125 operator = ( E2 * other ) noexcept 126 { reset(other); return *this; } 128 // copying assignments (in addition to compiler-generated copy assignment) 129 template< class E2 > 130 enable_if_t< is_compat<e2>(), exempt_ptr & > 131 operator = ( exempt_ptr<e2> const & other ) noexcept 132 { reset(other.get()); return *this; } 134 // observers 135 pointer get( ) const noexcept { return p; } 136 reference operator * ( ) const noexcept { return *get(); } 137 pointer operator -> ( ) const noexcept { return get(); } 138 explicit operator bool ( ) const noexcept { return get(); } 140 // conversions 141 operator pointer ( ) noexcept { return get(); } 142 operator const_pointer( ) const noexcept { return get(); } 144 // modifiers

6 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 145 pointer release( ) noexcept { pointer old = get(); reset(); return old; } 146 void reset( pointer t = nullptr ) noexcept { p = t; } 147 void swap( exempt_ptr & other ) noexcept { swap(p, other.p); } 149 // arithmetic 150 exempt_ptr & operator ++ ( ) { ++p; return *this; } 151 exempt_ptr & operator -- ( ) { --p; return *this; } 153 exempt_ptr operator ++ ( int ) { pointer tmp = p; ++p; return exempt_ptr{tmp}; } 154 exempt_ptr operator -- ( int ) { pointer tmp = p; --p; return exempt_ptr{tmp}; } 156 exempt_ptr operator + ( ) const { return *this; } 158 exempt_ptr operator + ( ptrdiff_t d ) const { return exempt_ptr{p+d}; } 159 exempt_ptr operator - ( ptrdiff_t d ) const { return exempt_ptr{p-d}; } 161 value_type & operator [] ( ptrdiff_t k ) { return p[k]; } 162 value_type const & operator [] ( ptrdiff_t k ) const { return p[k]; } 164 private: 165 pointer p; 167 }; // exempt_ptr<> 169 // ----------------------------------------------- 170 // exempt_ptr non-member swap 172 template< class E > 173 inline void 174 swap( exempt_ptr<e> & x, exempt_ptr<e> & y ) noexcept 175 { x.swap(y); } 177 // ----------------------------------------------- 178 // exempt_ptr non-member make_exempt 180 template< class E > 181 inline exempt_ptr<e> 182 make_exempt( E * p ) noexcept 183 { return exempt_ptr<e>{p}; } 185 // ----------------------------------------------- 186 // exempt_ptr non-member (in)equality operators 188 template< class E1, class E2 > 189 bool 190 operator == ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 191 { return equal_to<void>()(x.get(), y.get()); } 193 template< class E1, class E2 > 194 bool 195 operator!= ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 196 { return not operator == (x, y); } 198 template< class E >

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 7 199 bool 200 operator == ( exempt_ptr<e> const & x, nullptr_t y ) noexcept 201 { return x.get() == y; } 203 template< class E > 204 bool 205 operator!= ( exempt_ptr<e> const & x, nullptr_t y ) noexcept 206 { return not operator==(x, y); } 208 template< class E > 209 bool 210 operator == ( nullptr_t, exempt_ptr<e> const & y ) noexcept 211 { return x == y.get(); } 213 template< class E > 214 bool 215 operator!= ( nullptr_t x, exempt_ptr<e> const & y ) noexcept 216 { return not operator==(x, y); } 218 // ----------------------------------------------- 219 // exempt_ptr non-member ordering operators 221 template< class E1, class E2 > 222 bool 223 operator < ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 224 { return less<void>()(x.get(), y.get()); } 226 template< class E1, class E2 > 227 bool 228 operator > ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 229 { return y < x; } 231 template< class E1, class E2 > 232 bool 233 operator <= ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 234 { return not (y < x); } 236 template< class E1, class E2 > 237 bool 238 operator >= ( exempt_ptr<e1> const & x, exempt_ptr<e2> const & y ) 239 { return not (x < y); } 241 // ----------------------------------------------- 242 // exempt_ptr non-member arithmetic operators 244 template< class E > 245 exempt_ptr<e> 246 operator + ( ptrdiff_t d, exempt_ptr<e> const & p ) 247 { return p + d; } 249 template< class E > 250 ptrdiff_t 251 operator - ( exempt_ptr<e> const & x, exempt_ptr<e> const & y ) 252 { return x.get() - y.get(); }

8 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 4 Open questions 1. At the moment, exempt_ptr knows of no other smart pointer. Should exempt_ptr innately interoperate with any of the standard smart pointers? If so, with which one(s) and to what degree? 2. More generally, can LWG articulate a smart pointer interoperability policy or rationale in order to guide us in such decisions? 3. Alternative names 13 (shown alphabetically) for bike-shed consideration: aloof_ptr agnostic_ptr apolitical_ptr ascetic_ptr attending_ptr austere_ptr bare_ptr blameless_ptr blond_ptr blonde_ptr classic_ptr core_ptr disinterested_ptr disowned_ptr disowning_ptr dumb_ptr emancipated_ptr estranged_ptr excused_ptr faultless_ptr free_ptr freeagent_ptr guiltless_ptr handsoff_ptr ignorant_ptr impartial_ptr independent_ptr innocent_ptr irresponsible_ptr just_a_ptr legacy_ptr naked_ptr neutral_ptr nonown_ptr nonowning_ptr notme_ptr oblivious_ptr observer_ptr observing_ptr open_ptr ownerless_ptr pointer ptr pure_ptr quintessential_ptr severe_ptr simple_ptr stark_ptr straight_ptr true_ptr unfettered_ptr uninvolved_ptr unmanaged_ptr unowned_ptr untainted_ptr unyoked_ptr virgin_ptr visiting_ptr watch_ptr watcher_ptr watching_ptr witless_ptr witness_ptr 5 Proposed wording 14 5.1 Synopsis Append the following, in namespace std, to [memory.syn]: // 20.8.x, class template exempt_ptr class exempt_ptr; void swap(const exempt_ptr<e>&, const exempt_ptr<e>&) noexcept; exempt_ptr<e> make_exempt(e*) noexcept; // (in)equality operators bool operator==(const exempt_ptr<e1>&, const exempt_ptr<e2>&); 13 Most of these names were suggested by readers of earlier drafts. While not all suggestions seem viable (e.g., some are clearly intended as humorous), we have opted to preserve all of them for the record. 14 All wording is relative to Working Draft N3691.

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 9 bool operator!=(const exempt_ptr<e1>&, const exempt_ptr<e2>&); bool operator==(const exempt_ptr<e>&, nullptr_t) noexcept; bool operator!=(const exempt_ptr<e>&, nullptr_t) noexcept; bool operator==(nullptr_t, const exempt_ptr<e>&) noexcept; bool operator!=(nullptr_t, const exempt_ptr<e>&) noexcept; // ordering operators bool operator<(const exempt_ptr<e1>&, const exempt_ptr<e2>&); bool operator>(const exempt_ptr<e1>&, const exempt_ptr<e2>&); bool operator<=(const exempt_ptr<e1>&, const exempt_ptr<e2>&); bool operator>=(const exempt_ptr<e1>&, const exempt_ptr<e2>&); // arithmetic operators exempt_ptr<e> operator+(ptrdiff_t, const exempt_ptr<e>&); template< class E > ptrdiff_t operator-(const exempt_ptr<e>&, const exempt_ptr<e>& ); 5.2 Class template, etc. Create in [smartptr] a new subclause as follows: 20.8.x Non-owning pointers 1 A non-owning pointer, also known as an observer or watcher, is an object o that stores a pointer to a second object w. In this context, w is known as a watched object. [ Note: There is no watched object when the stored pointer is nullptr. end note ] An observer takes no responsibility or ownership of any kind for the watched object, if any. In particular, there is no inherent relationship between the lifetimes of any observer and any watched objects. 2 Each type instantiated from the exempt_ptr template specified in this subclause shall meet the requirements of a CopyConstructible and CopyAssignable type. The template parameter E of exempt_ptr may be an incomplete type. 3 [ Note: The uses of exempt_ptr include clarity of interface specification in new code, and interoperability with pointer-based legacy code. end note ] Following the practice of C++11, another copy of the synopsis above is to be inserted here. However, comments are omitted from this copy.

10 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 20.8.x.1 Class template exempt_ptr [exempt.ptr] 1 For the purposes of this subclause, a type F is said to be pointer-incompatible with a type E if the expression is_convertible< add_pointer_t<f>, add_pointer_t<e> >::value is false. namespace std { class exempt_ptr { public: // publish our template parameter and variations thereof using value_type = E; using pointer = add_pointer_t<e>; using const_pointer = add_pointer_t<const E>; using reference = add_lvalue_reference_t<e>; using const_reference = add_lvalue_reference_t<const E>; // enable use as a pointer-like iterator using difference_type = ptrdiff_t; using iterator_category = random_access_iterator_tag; // default c tor constexpr exempt_ptr() noexcept; // pointer-accepting c tors constexpr exempt_ptr(nullptr_t) noexcept; explicit exempt_ptr(pointer) noexcept; template <class E2> explicit exempt_ptr(e2*) noexcept; // copying c tors (in addition to compiler-generated copy c tor) template <class E2> exempt_ptr(const exempt_ptr<e2>&) noexcept; // pointer-accepting assignments exempt_ptr& operator=(nullptr_t) noexcept; template <class E2> exempt_ptr& operator=(e2* other) noexcept; // copying assignments (in addition to compiler-generated copy assignment) template <class E2> exempt_ptr& operator=(const exempt_ptr<e2>&) noexcept; // observers pointer get() const noexcept; reference operator*() const noexcept; pointer operator->() const noexcept; explicit operator bool() const noexcept; // conversions operator pointer() noexcept; operator const_pointer() const noexcept; // modifiers pointer release() noexcept; void reset(pointer t = nullptr) noexcept; void swap(exempt_ptr&) noexcept; // arithmetic exempt_ptr& operator++(); exempt_ptr& operator--();

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 11 exempt_ptr operator++(int); exempt_ptr operator--(int); exempt_ptr operator+() const; exempt_ptr operator+(ptrdiff_t) const; exempt_ptr operator-(ptrdiff_t) const; value_type& operator[](ptrdiff_t); const value_type& operator[](ptrdiff_t) const; }; // exempt_ptr<> } 20.8.x.1.1 exempt_ptr constructors constexpr exempt_ptr() noexcept; constexpr exempt_ptr(nullptr_t) noexcept; [exempt.ptr.ctor] 1 Effects: Constructs an exempt_ptr object that has no corresponding watched object. 2 Postconditions: get() == nullptr. explicit exempt_ptr(pointer other) noexcept; 3 Effects: Constructs an exempt_ptr object whose watched object is *other. template <class E2> explicit exempt_ptr(e2* other) noexcept; 4 Effects: Constructs an exempt_ptr object whose watched object is *dynamic_cast<pointer >(other). 5 Remarks: This constructor shall not participate in overload resolution if E2 is pointer-incompatible with E. template <class E2> exempt_ptr(const exempt_ptr<e2>& other) noexcept; 6 Effects: Constructs an exempt_ptr object whose watched object is *dynamic_cast<pointer >(other). 7 Remarks: This constructor shall not participate in overload resolution if E2 is pointer-incompatible with E. 20.8.x.1.2 exempt_ptr assignment exempt_ptr& operator=(nullptr_t) noexcept; 1 Effects: Same as if calling reset(nullptr); 2 Returns: *this. template <class E2> exempt_ptr& operator=(e2* other) noexcept; 3 Effects: Same as if calling reset(other); 4 Returns: *this. [exempt.ptr.assign] 5 Remarks: This operator shall not participate in overload resolution if E2 is pointer-incompatible with E. template <class E2> exempt_ptr& operator=(const exempt_ptr<e2>& other) noexcept; 6 Effects: Same as if calling reset(other.get()); 7 Returns: *this.

12 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 8 Remarks: This operator shall not participate in overload resolution if E2 is pointer-incompatible with E. 20.8.x.1.3 exempt_ptr observers pointer get() const noexcept; 1 Returns: The stored pointer. reference operator*() const noexcept; 2 Requires: get()!= nullptr. 3 Returns: *get(). pointer operator->() const noexcept; 4 Requires: get()!= nullptr. 5 Returns: get(). explicit operator bool() const noexcept; [exempt.ptr.obs] 6 Returns: get()!= nullptr. 20.8.x.1.4 exempt_ptr conversions operator pointer() noexcept; [exempt.ptr.conv] 1 Returns: get(). operator const_pointer() const noexcept; 2 Returns: get(). 20.8.x.1.5 exempt_ptr modifiers pointer release() noexcept; [exempt.ptr.mod] 1 Postconditions: get() == nullptr. 2 Returns: The value get() had at the start of the call to release. void reset(pointer p = nullptr) noexcept; 3 Postconditions: get() == p. void swap(exempt_ptr& other) noexcept; 4 Effects: Invokes swap on the stored pointers of *this and other. 20.8.x.1.6 exempt_ptr arithmetic exempt_ptr& operator++(); exempt_ptr& operator--(); [exempt.ptr.arith] 1 Effects: Increments (or, in the second form, decrements) the stored pointer. 2 Requires: get()!= nullptr. 3 Returns: *this. exempt_ptr operator++(int); exempt_ptr operator--(int);

N3740: A Proposal for the World s Dumbest Smart Pointer, v2 13 4 Effects: Increments (or, in the second form, decrements) the stored pointer. 5 Requires: get()!= nullptr. 6 Returns: exempt_ptr(p++) or exempt_ptr(p--), respectively, where p denotes the original stored pointer. exempt_ptr operator+() const; 7 Returns: *this. exempt_ptr operator+(ptrdiff_t d) const; exempt_ptr operator-(ptrdiff_t d) const; 8 Returns: exempt_ptr(p+d) or exempt_ptr(p-d), respectively, where p denotes the stored pointer. value_type& operator[](ptrdiff_t k); const value_type& operator[](ptrdiff_t k); 9 Returns: p[k], where p denotes the stored pointer. 20.8.x.1.7 exempt_ptr specialized algorithms void swap(exempt_ptr<e> & p1, exempt_ptr<e> & p2) noexcept; 1 Effects: p1.swap(p2). exempt_ptr<e> make_exempt(e * p) noexcept; 2 Returns: exempt_ptr<e>{p}. [exempt.ptr.special] bool operator==(exempt_ptr<e1> const & p1, exempt_ptr<e2> const & p2); 3 Returns: equal_to<void>()(p1.get(), p2.get()). bool operator!=(exempt_ptr<e1> const & p1, exempt_ptr<e2> const & p2); 4 Returns: not operator==(p1, p2). bool operator==(exempt_ptr<e> const & p, nullptr_t) noexcept; bool operator==(nullptr_t, exempt_ptr<e> const & p) noexcept; 5 Returns: not p. bool operator!=(exempt_ptr<e> const & p, nullptr_t) noexcept; bool operator!=(nullptr_t, exempt_ptr<e> const & p) noexcept; 6 Returns: (bool)p. bool operator<(exempt_ptr<e1> const & p1, exempt_ptr<e2> const & p2); 7 Returns: less<void>()(x.get(), y.get());.

14 N3740: A Proposal for the World s Dumbest Smart Pointer, v2 bool operator>(exempt_ptr<e> const & p1, exempt_ptr<e> const & p2); 8 Returns: p2 < p1. bool operator<=(exempt_ptr<e> const & p1, exempt_ptr<e> const & p2); 9 Returns: not (p2 < p1). bool operator>=(exempt_ptr<e> const & p1, exempt_ptr<e> const & p2); 10 Returns: not (p1 < p2). template< class E > exempt_ptr<e> operator+(ptrdiff_t d, exempt_ptr<e> const & p) 11 Returns: (p + d). template< class E > ptrdiff_t operator-(const exempt_ptr<e>& p1, const exempt_ptr<e>& p2) 12 Returns: p1.get() - p2.get() 6 Acknowledgments Many thanks to the reviewers of early drafts of this paper for their helpful and constructive comments. 7 Revision history Version Date Changes 1 2012-12-19 Published as N3514. 2 2013-08-30 Added this Revision history section. Augmented the proposal with conversion and arithmetic operators. Removed two no-longer-open questions. Consolidated all proposed wording into a single section. Updated code for C++14 compliance. Reflected C++14 status of optional proposal. Augmented the proposal with additional member typedefs. Published as N3740.