Files
cppdraft_translate/cppdraft/smartptr/adapt.md
2025-10-25 03:02:53 +03:00

17 KiB
Raw Blame History

[smartptr.adapt]

20 Memory management library [mem]

20.3 Smart pointers [smartptr]

20.3.4 Smart pointer adaptors [smartptr.adapt]

20.3.4.1 Class template out_ptr_t [out.ptr.t]

1

#

out_ptr_t is a class template used to adapt types such as smart pointers ([smartptr]) for functions that use output pointer parameters.

2

#

[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<std::FILE, fclose_deleter> file_ptr; int err = fopen_s(std::out_ptrstd::FILE*(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.

— end example]

🔗

namespace std {template<class Smart, class Pointer, class... Args>class 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<Args...> a; // exposition only Pointer p; // exposition only};}

3

#

Pointer shall meet the Cpp17NullablePointer requirements.

If Smart is a specialization of shared_ptr andsizeof...(Args) == 0, the program is ill-formed.

[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].

— end note]

4

#

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.

5

#

Evaluations of the conversion functions on the same object may conflict ([intro.races]).

🔗

constexpr explicit out_ptr_t(Smart& smart, Args... args);

6

#

Effects: Initializes s with smart,a with std::forward(args)..., and value-initializes p.

Then, equivalent to:

s.reset(); if the expression s.reset() is well-formed;

otherwise,s = Smart(); if is_constructible_v is true;

otherwise, the program is ill-formed.

7

#

[Note 2:

The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies.

For example, an implementation can allocate a shared_ptr's internal node in the constructor and let implementation-defined exceptions escape safely.

The destructor can then move the allocated control block in directly and avoid any other exceptions.

— end note]

🔗

constexpr ~out_ptr_t();

8

#

Let SP bePOINTER_OF_OR(Smart, Pointer) ([memory.general]).

9

#

Effects: Equivalent to:

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;

otherwise,if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a));} if is_constructible_v<Smart, SP, Args...> is true;

otherwise, the program is ill-formed.

🔗

constexpr operator Pointer*() const noexcept;

10

#

Preconditions: operator void**() has not been called on *this.

11

#

Returns: addressof(const_cast<Pointer&>(p)).

🔗

operator void**() const noexcept;

12

#

Constraints: is_same_v<Pointer, void*> is false.

13

#

Mandates: is_pointer_v is true.

14

#

Preconditions: operator Pointer*() has not been called on *this.

15

#

Returns: A pointer value v such that:

the initial value v is equivalent to static_cast<void>(p) and

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<void>(p) == *v.

16

#

Remarks: Accessing *v outside the lifetime of *this has undefined behavior.

17

#

[Note 3:

reinterpret_cast<void**>(static_cast<Pointer*>(*this)) can be a viable implementation strategy for some implementations.

— end note]

20.3.4.2 Function template out_ptr [out.ptr]

🔗

template<class Pointer = void, class Smart, class... Args> constexpr auto out_ptr(Smart& s, Args&&... args);

1

#

Let P be Pointer if is_void_v is false, otherwise POINTER_OF(Smart).

2

#

Returns: out_ptr_t<Smart, P, Args&&...>(s, std::forward(args)...).

20.3.4.3 Class template inout_ptr_t [inout.ptr.t]

1

#

inout_ptr_t is a class template used to adapt types such as smart pointers ([smartptr]) for functions that use output pointer parameters whose dereferenced values may first be deleted before being set to another allocated value.

2

#

[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<star_fish, star_fish_deleter>;

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.

The original value will be properly deleted according to the function it is used with and a new value reset in its place.

— end example]

🔗

namespace std {template<class Smart, class Pointer, class... Args>class 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<Args...> a; // exposition only Pointer p; // exposition only};}

3

#

Pointer shall meet the Cpp17NullablePointer requirements.

If Smart is a specialization of shared_ptr, the program is ill-formed.

[Note 1:

It is impossible to properly acquire unique ownership of the managed resource from a shared_ptr given its shared ownership model.

— end note]

4

#

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.

5

#

Evaluations of the conversion functions on the same object may conflict ([intro.races]).

🔗

constexpr explicit inout_ptr_t(Smart& smart, Args... args);

6

#

Effects: Initializes s with smart,a with std::forward(args)..., andp to either

smart if is_pointer_v is true,

otherwise, smart.get().

7

#

Remarks: An implementation can call s.release().

8

#

[Note 2:

The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies.

For example, an intrusive pointer implementation with a control block can allocate in the constructor and safely fail with an exception.

— end note]

🔗

constexpr ~inout_ptr_t();

9

#

Let SP bePOINTER_OF_OR(Smart, Pointer) ([memory.general]).

10

#

Let release-statement be s.release(); if an implementation does not call s.release() in the constructor.

Otherwise, it is empty.

11

#

Effects: Equivalent to:

apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); if is_pointer_v is true;

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;

otherwise,release-statement;if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a));} if is_constructible_v<Smart, SP, Args...> is true;

otherwise, the program is ill-formed.

🔗

constexpr operator Pointer*() const noexcept;

12

#

Preconditions: operator void**() has not been called on *this.

13

#

Returns: addressof(const_cast<Pointer&>(p)).

🔗

operator void**() const noexcept;

14

#

Constraints: is_same_v<Pointer, void*> is false.

15

#

Mandates: is_pointer_v is true.

16

#

Preconditions: operator Pointer*() has not been called on *this.

17

#

Returns: A pointer value v such that:

the initial value v is equivalent to static_cast<void>(p) and

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<void>(p) == *v.

18

#

Remarks: Accessing *v outside the lifetime of *this has undefined behavior.

19

#

[Note 3:

reinterpret_cast<void**>(static_cast<Pointer*>(*this)) can be a viable implementation strategy for some implementations.

— end note]

20.3.4.4 Function template inout_ptr [inout.ptr]

🔗

template<class Pointer = void, class Smart, class... Args> constexpr auto inout_ptr(Smart& s, Args&&... args);

1

#

Let P be Pointer if is_void_v is false, otherwise POINTER_OF(Smart).

2

#

Returns: inout_ptr_t<Smart, P, Args&&...>(s, std::forward(args)...).