[smartptr.adapt] # 20 Memory management library [[mem]](./#mem) ## 20.3 Smart pointers [[smartptr]](smartptr#adapt) ### 20.3.4 Smart pointer adaptors [smartptr.adapt] #### [20.3.4.1](#out.ptr.t) Class template out_ptr_t [[out.ptr.t]](out.ptr.t) [1](#out.ptr.t-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5423) out_ptr_t is a class template used to adapt types such as smart pointers ([[smartptr]](smartptr "20.3 Smart pointers")) for functions that use output pointer parameters[.](#out.ptr.t-1.sentence-1) [2](#out.ptr.t-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5428) [*Example [1](#out.ptr.t-example-1)*: #include #include int fopen_s(std::FILE** f, const char* name, const char* mode); struct fclose_deleter {void operator()(std::FILE* f) const noexcept { std::fclose(f); }}; int main(int, char*[]) {constexpr const char* file_name = "ow.o"; std::unique_ptr file_ptr; int err = fopen_s(std::out_ptr(file_ptr), file_name, "r+b"); if (err != 0)return 1; // *file_ptr is validreturn 0;}unique_ptr can be used with out_ptr to be passed into an output pointer-style function, without needing to hold onto an intermediate pointer value and manually delete it on error or failure[.](#out.ptr.t-2.sentence-1) — *end example*] [🔗](#lib:out_ptr_t) namespace std {templateclass out_ptr_t {public:constexpr explicit out_ptr_t(Smart&, Args...); out_ptr_t(const out_ptr_t&) = delete; constexpr ~out_ptr_t(); constexpr operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // *exposition only* tuple a; // *exposition only* Pointer p; // *exposition only*};} [3](#out.ptr.t-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5480) Pointer shall meet the [*Cpp17NullablePointer*](nullablepointer.requirements#:Cpp17NullablePointer "16.4.4.4 Cpp17NullablePointer requirements [nullablepointer.requirements]") requirements[.](#out.ptr.t-3.sentence-1) If Smart is a specialization of shared_ptr andsizeof...(Args) == 0, the program is ill-formed[.](#out.ptr.t-3.sentence-2) [*Note [1](#out.ptr.t-note-1)*: It is typically a user error to reset a shared_ptr without specifying a deleter, as shared_ptr will replace a custom deleter upon usage of reset, as specified in [[util.smartptr.shared.mod]](util.smartptr.shared.mod "20.3.2.2.5 Modifiers")[.](#out.ptr.t-3.sentence-3) — *end note*] [4](#out.ptr.t-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5492) Program-defined specializations of out_ptr_t that depend on at least one program-defined type need not meet the requirements for the primary template[.](#out.ptr.t-4.sentence-1) [5](#out.ptr.t-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5497) Evaluations of the conversion functions on the same object may conflict ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#out.ptr.t-5.sentence-1) [🔗](#lib:out_ptr_t,constructor) `constexpr explicit out_ptr_t(Smart& smart, Args... args); ` [6](#out.ptr.t-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5507) *Effects*: Initializes s with smart,a with std​::​forward(args)..., and value-initializes p[.](#out.ptr.t-6.sentence-1) Then, equivalent to: - [(6.1)](#out.ptr.t-6.1) s.reset(); if the expression s.reset() is well-formed; - [(6.2)](#out.ptr.t-6.2) otherwise,s = Smart(); if is_constructible_v is true; - [(6.3)](#out.ptr.t-6.3) otherwise, the program is ill-formed[.](#out.ptr.t-6.sentence-2) [7](#out.ptr.t-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5533) [*Note [2](#out.ptr.t-note-2)*: The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies[.](#out.ptr.t-7.sentence-1) For example, an implementation can allocate a shared_ptr's internal node in the constructor and let implementation-defined exceptions escape safely[.](#out.ptr.t-7.sentence-2) The destructor can then move the allocated control block in directly and avoid any other exceptions[.](#out.ptr.t-7.sentence-3) — *end note*] [🔗](#lib:out_ptr_t,destructor) `constexpr ~out_ptr_t(); ` [8](#out.ptr.t-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5551) Let SP be*POINTER_OF_OR*(Smart, Pointer) ([[memory.general]](memory.general "20.2.1 General"))[.](#out.ptr.t-8.sentence-1) [9](#out.ptr.t-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5555) *Effects*: Equivalent to: - [(9.1)](#out.ptr.t-9.1) if (p) { apply([&](auto&&... args) { s.reset(static_cast(p), std::forward(args)...); }, std::move(a));} if the expressions.reset(static_cast(p), std​::​forward(args)...) is well-formed; - [(9.2)](#out.ptr.t-9.2) otherwise,if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a));} if is_constructible_v is true; - [(9.3)](#out.ptr.t-9.3) otherwise, the program is ill-formed[.](#out.ptr.t-9.sentence-1) [🔗](#out.ptr.t-itemdecl:3) `constexpr operator Pointer*() const noexcept; ` [10](#out.ptr.t-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5590) *Preconditions*: operator void**() has not been called on *this[.](#out.ptr.t-10.sentence-1) [11](#out.ptr.t-11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5594) *Returns*: addressof(const_cast(p))[.](#out.ptr.t-11.sentence-1) [🔗](#out.ptr.t-itemdecl:4) `operator void**() const noexcept; ` [12](#out.ptr.t-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5604) *Constraints*: is_same_v is false[.](#out.ptr.t-12.sentence-1) [13](#out.ptr.t-13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5608) *Mandates*: is_pointer_v is true[.](#out.ptr.t-13.sentence-1) [14](#out.ptr.t-14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5612) *Preconditions*: operator Pointer*() has not been called on *this[.](#out.ptr.t-14.sentence-1) [15](#out.ptr.t-15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5616) *Returns*: A pointer value v such that: - [(15.1)](#out.ptr.t-15.1) the initial value *v is equivalent to static_cast(p) and - [(15.2)](#out.ptr.t-15.2) any modification of *v that is not followed by a subsequent modification of *this affects the value of p during the destruction of *this, such that static_cast(p) == *v[.](#out.ptr.t-15.sentence-1) [16](#out.ptr.t-16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5629) *Remarks*: Accessing *v outside the lifetime of *this has undefined behavior[.](#out.ptr.t-16.sentence-1) [17](#out.ptr.t-17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5634) [*Note [3](#out.ptr.t-note-3)*: reinterpret_cast(static_cast(*this)) can be a viable implementation strategy for some implementations[.](#out.ptr.t-17.sentence-1) — *end note*] #### [20.3.4.2](#out.ptr) Function template out_ptr [[out.ptr]](out.ptr) [🔗](#lib:out_ptr) `template constexpr auto out_ptr(Smart& s, Args&&... args); ` [1](#out.ptr-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5650) Let P be Pointer if is_void_v is false, otherwise *POINTER_OF*(Smart)[.](#out.ptr-1.sentence-1) [2](#out.ptr-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5655) *Returns*: out_ptr_t(s, std​::​forward(args)...)[.](#out.ptr-2.sentence-1) #### [20.3.4.3](#inout.ptr.t) Class template inout_ptr_t [[inout.ptr.t]](inout.ptr.t) [1](#inout.ptr.t-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5662) inout_ptr_t is a class template used to adapt types such as smart pointers ([[smartptr]](smartptr "20.3 Smart pointers")) for functions that use output pointer parameters whose dereferenced values may first be deleted before being set to another allocated value[.](#inout.ptr.t-1.sentence-1) [2](#inout.ptr.t-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5669) [*Example [1](#inout.ptr.t-example-1)*: #include struct star_fish* star_fish_alloc();int star_fish_populate(struct star_fish** ps, const char* description); struct star_fish_deleter {void operator() (struct star_fish* c) const noexcept;}; using star_fish_ptr = std::unique_ptr; int main(int, char*[]) { star_fish_ptr peach(star_fish_alloc()); // ...// used, need to re-makeint err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker"); return err;} A unique_ptr can be used with inout_ptr to be passed into an output pointer-style function[.](#inout.ptr.t-2.sentence-1) The original value will be properly deleted according to the function it is used with and a new value reset in its place[.](#inout.ptr.t-2.sentence-2) — *end example*] [🔗](#lib:inout_ptr_t) namespace std {templateclass inout_ptr_t {public:constexpr explicit inout_ptr_t(Smart&, Args...); inout_ptr_t(const inout_ptr_t&) = delete; constexpr ~inout_ptr_t(); constexpr operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // *exposition only* tuple a; // *exposition only* Pointer p; // *exposition only*};} [3](#inout.ptr.t-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5720) Pointer shall meet the [*Cpp17NullablePointer*](nullablepointer.requirements#:Cpp17NullablePointer "16.4.4.4 Cpp17NullablePointer requirements [nullablepointer.requirements]") requirements[.](#inout.ptr.t-3.sentence-1) If Smart is a specialization of shared_ptr, the program is ill-formed[.](#inout.ptr.t-3.sentence-2) [*Note [1](#inout.ptr.t-note-1)*: It is impossible to properly acquire unique ownership of the managed resource from a shared_ptr given its shared ownership model[.](#inout.ptr.t-3.sentence-3) — *end note*] [4](#inout.ptr.t-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5729) Program-defined specializations of inout_ptr_t that depend on at least one program-defined type need not meet the requirements for the primary template[.](#inout.ptr.t-4.sentence-1) [5](#inout.ptr.t-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5734) Evaluations of the conversion functions on the same object may conflict ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#inout.ptr.t-5.sentence-1) [🔗](#lib:inout_ptr_t,constructor) `constexpr explicit inout_ptr_t(Smart& smart, Args... args); ` [6](#inout.ptr.t-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5744) *Effects*: Initializes s with smart,a with std​::​forward(args)..., andp to either - [(6.1)](#inout.ptr.t-6.1) smart if is_pointer_v is true, - [(6.2)](#inout.ptr.t-6.2) otherwise, smart.get()[.](#inout.ptr.t-6.sentence-1) [7](#inout.ptr.t-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5754) *Remarks*: An implementation can call s.release()[.](#inout.ptr.t-7.sentence-1) [8](#inout.ptr.t-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5758) [*Note [2](#inout.ptr.t-note-2)*: The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies[.](#inout.ptr.t-8.sentence-1) For example, an intrusive pointer implementation with a control block can allocate in the constructor and safely fail with an exception[.](#inout.ptr.t-8.sentence-2) — *end note*] [🔗](#lib:inout_ptr_t,destructor) `constexpr ~inout_ptr_t(); ` [9](#inout.ptr.t-9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5773) Let SP be*POINTER_OF_OR*(Smart, Pointer) ([[memory.general]](memory.general "20.2.1 General"))[.](#inout.ptr.t-9.sentence-1) [10](#inout.ptr.t-10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5777) Let *release-statement* be s.release(); if an implementation does not call s.release() in the constructor[.](#inout.ptr.t-10.sentence-1) Otherwise, it is empty[.](#inout.ptr.t-10.sentence-2) [11](#inout.ptr.t-11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5782) *Effects*: Equivalent to: - [(11.1)](#inout.ptr.t-11.1) apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); if is_pointer_v is true; - [(11.2)](#inout.ptr.t-11.2) otherwise,*release-statement*;if (p) { apply([&](auto&&... args) { s.reset(static_cast(p), std::forward(args)...); }, std::move(a));} if the expressions.reset(static_cast(p), std​::​forward(args)...) is well- formed; - [(11.3)](#inout.ptr.t-11.3) otherwise,*release-statement*;if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a));} if is_constructible_v is true; - [(11.4)](#inout.ptr.t-11.4) otherwise, the program is ill-formed[.](#inout.ptr.t-11.sentence-1) [🔗](#inout.ptr.t-itemdecl:3) `constexpr operator Pointer*() const noexcept; ` [12](#inout.ptr.t-12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5826) *Preconditions*: operator void**() has not been called on *this[.](#inout.ptr.t-12.sentence-1) [13](#inout.ptr.t-13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5830) *Returns*: addressof(const_cast(p))[.](#inout.ptr.t-13.sentence-1) [🔗](#inout.ptr.t-itemdecl:4) `operator void**() const noexcept; ` [14](#inout.ptr.t-14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5840) *Constraints*: is_same_v is false[.](#inout.ptr.t-14.sentence-1) [15](#inout.ptr.t-15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5844) *Mandates*: is_pointer_v is true[.](#inout.ptr.t-15.sentence-1) [16](#inout.ptr.t-16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5848) *Preconditions*: operator Pointer*() has not been called on *this[.](#inout.ptr.t-16.sentence-1) [17](#inout.ptr.t-17) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5852) *Returns*: A pointer value v such that: - [(17.1)](#inout.ptr.t-17.1) the initial value *v is equivalent to static_cast(p) and - [(17.2)](#inout.ptr.t-17.2) any modification of *v that is not followed by subsequent modification of *this affects the value of p during the destruction of *this, such that static_cast(p) == *v[.](#inout.ptr.t-17.sentence-1) [18](#inout.ptr.t-18) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5865) *Remarks*: Accessing *v outside the lifetime of *this has undefined behavior[.](#inout.ptr.t-18.sentence-1) [19](#inout.ptr.t-19) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5870) [*Note [3](#inout.ptr.t-note-3)*: reinterpret_cast(static_cast(*this)) can be a viable implementation strategy for some implementations[.](#inout.ptr.t-19.sentence-1) — *end note*] #### [20.3.4.4](#inout.ptr) Function template inout_ptr [[inout.ptr]](inout.ptr) [🔗](#lib:inout_ptr) `template constexpr auto inout_ptr(Smart& s, Args&&... args); ` [1](#inout.ptr-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5886) Let P be Pointer if is_void_v is false, otherwise *POINTER_OF*(Smart)[.](#inout.ptr-1.sentence-1) [2](#inout.ptr-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L5890) *Returns*: inout_ptr_t(s, std​::​forward(args)...)[.](#inout.ptr-2.sentence-1)