Difference between revisions of "cpp/memory/to address"
(Update possible implementation) |
(Link concept (and remove invisible character), to_address isn't disallowed on other iterators, it's just not guaranteed to be supported) |
||
(11 intermediate revisions by 8 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/memory/navbar}} | {{cpp/memory/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | memory}} | + | {{dcl header|memory}} |
− | {{dcl |num=1|since=c++20|1= | + | {{dcl|num=1|since=c++20|1= |
template< class Ptr > | template< class Ptr > | ||
− | auto to_address(const Ptr& p) noexcept; | + | constexpr auto to_address( const Ptr& p ) noexcept; |
}} | }} | ||
− | {{dcl | num=2 | since=c++20 |1= | + | {{dcl|num=2|since=c++20|1= |
template< class T > | template< class T > | ||
− | constexpr T* to_address(T* p) noexcept; | + | constexpr T* to_address( T* p ) noexcept; |
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | Obtain the address represented by {{ | + | Obtain the address represented by {{c|p}} without forming a reference to the object pointed to by {{c|p}}. |
− | @1@ Fancy pointer overload: If the expression {{c|std::pointer_traits<Ptr>::to_address(p)}} is well-formed, returns the result of that expression. Otherwise, returns {{c|std::to_address(p.operator->())}}. | + | @1@ [[cpp/named_req/Allocator#Fancy pointers|Fancy pointer]] overload: If the expression {{c|std::pointer_traits<Ptr>::to_address(p)}} is well-formed, returns the result of that expression. Otherwise, returns {{c|std::to_address(p.operator->())}}. |
@2@ Raw pointer overload: If {{tt|T}} is a function type, the program is ill-formed. Otherwise, returns {{c|p}} unmodified. | @2@ Raw pointer overload: If {{tt|T}} is a function type, the program is ill-formed. Otherwise, returns {{c|p}} unmodified. | ||
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
− | {{par | p | fancy or raw pointer}} | + | {{par|p|fancy or raw pointer}} |
{{par end}} | {{par end}} | ||
===Return value=== | ===Return value=== | ||
− | Raw pointer that represents the same address as {{ | + | Raw pointer that represents the same address as {{c|p}} does. |
===Possible implementation=== | ===Possible implementation=== | ||
− | {{eq fun | 1= | + | {{eq fun|1= |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
template<class T> | template<class T> | ||
constexpr T* to_address(T* p) noexcept | constexpr T* to_address(T* p) noexcept | ||
{ | { | ||
− | static_assert(!is_function_v<T>); | + | static_assert(!std::is_function_v<T>); |
return p; | return p; | ||
} | } | ||
template<class T> | template<class T> | ||
− | auto to_address(const T& p) noexcept | + | constexpr auto to_address(const T& p) noexcept |
{ | { | ||
− | if constexpr ( | + | if constexpr (requires{ std::pointer_traits<T>::to_address(p); }) |
− | return pointer_traits<T>::to_address(p); | + | return std::pointer_traits<T>::to_address(p); |
− | + | else | |
− | return to_address(p.operator->()); | + | return std::to_address(p.operator->()); |
− | + | ||
} | } | ||
}} | }} | ||
===Notes=== | ===Notes=== | ||
− | {{tt|std::to_address}} can be used even when {{ | + | {{tt|std::to_address}} can be used even when {{c|p}} does not reference storage that has an object constructed in it, in which case {{c|std::addressof(*p)}} cannot be used because there is no valid object for the parameter of {{c|std::addressof}}<!--or the return value of fancy_pointer::operator* --> to bind to. |
+ | |||
+ | The fancy pointer overload of {{tt|std::to_address}} inspects the {{c|std::pointer_traits<Ptr>}} specialization. If instantiating that specialization is itself ill-formed (typically because {{tt|element_type}} cannot be defined), that results in a hard error outside the immediate context and renders the program ill-formed. | ||
+ | |||
+ | {{tt|std::to_address}} may additionally be used on iterators that satisfy {{lc|std::contiguous_iterator}}. | ||
+ | |||
+ | {{feature test macro|__cpp_lib_to_address|Utility to convert a pointer to a raw pointer ({{tt|std::to_address}})|value=201711L|std=C++20}} | ||
===Example=== | ===Example=== | ||
Line 65: | Line 62: | ||
{ | { | ||
auto p = a.allocate(1); | auto p = a.allocate(1); | ||
− | try { | + | try |
+ | { | ||
std::allocator_traits<A>::construct(a, std::to_address(p)); | std::allocator_traits<A>::construct(a, std::to_address(p)); | ||
− | } catch (...) { | + | } |
+ | catch (...) | ||
+ | { | ||
a.deallocate(p, 1); | a.deallocate(p, 1); | ||
throw; | throw; | ||
Line 91: | Line 91: | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/memory/dsc pointer_traits}} | + | {{dsc inc|cpp/memory/dsc pointer_traits}} |
− | {{dsc inc | cpp/memory/pointer_traits/dsc to_address}} | + | {{dsc inc|cpp/memory/pointer_traits/dsc to_address}} |
{{dsc end}} | {{dsc end}} | ||
{{langlinks|ar|de|es|fr|it|ja|pl|pt|ru|zh}} | {{langlinks|ar|de|es|fr|it|ja|pl|pt|ru|zh}} |
Latest revision as of 01:31, 12 July 2023
Defined in header <memory>
|
||
template< class Ptr > constexpr auto to_address( const Ptr& p ) noexcept; |
(1) | (since C++20) |
template< class T > constexpr T* to_address( T* p ) noexcept; |
(2) | (since C++20) |
Obtain the address represented by p without forming a reference to the object pointed to by p.
T
is a function type, the program is ill-formed. Otherwise, returns p unmodified.Contents |
[edit] Parameters
p | - | fancy or raw pointer |
[edit] Return value
Raw pointer that represents the same address as p does.
[edit] Possible implementation
template<class T> constexpr T* to_address(T* p) noexcept { static_assert(!std::is_function_v<T>); return p; } template<class T> constexpr auto to_address(const T& p) noexcept { if constexpr (requires{ std::pointer_traits<T>::to_address(p); }) return std::pointer_traits<T>::to_address(p); else return std::to_address(p.operator->()); } |
[edit] Notes
std::to_address
can be used even when p does not reference storage that has an object constructed in it, in which case std::addressof(*p) cannot be used because there is no valid object for the parameter of std::addressof to bind to.
The fancy pointer overload of std::to_address
inspects the std::pointer_traits<Ptr> specialization. If instantiating that specialization is itself ill-formed (typically because element_type
cannot be defined), that results in a hard error outside the immediate context and renders the program ill-formed.
std::to_address
may additionally be used on iterators that satisfy std::contiguous_iterator.
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_to_address |
201711L | (C++20) | Utility to convert a pointer to a raw pointer (std::to_address )
|
[edit] Example
#include <memory> template<class A> auto allocator_new(A& a) { auto p = a.allocate(1); try { std::allocator_traits<A>::construct(a, std::to_address(p)); } catch (...) { a.deallocate(p, 1); throw; } return p; } template<class A> void allocator_delete(A& a, typename std::allocator_traits<A>::pointer p) { std::allocator_traits<A>::destroy(a, std::to_address(p)); a.deallocate(p, 1); } int main() { std::allocator<int> a; auto p = allocator_new(a); allocator_delete(a, p); }
[edit] See also
(C++11) |
provides information about pointer-like types (class template) |
[static] (C++20)(optional) |
obtains a raw pointer from a fancy pointer (inverse of pointer_to ) (public static member function of std::pointer_traits<Ptr> )
|