memory_to_address

memory_to_address (std::to_address)

<memory> 헤더에 정의되어 있어요. p가 가리키는 객체에 대한 참조를 만들지 않고 p가 나타내는 주소를 얻어요. fancy pointer와 원시 포인터 모두에 쓸 수 있어요. C++20부터 도입됐어요.

출처: cppreference

본문

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

p가 가리키는 객체에 대한 참조를 형성하지 않고 p가 나타내는 주소를 얻어요.

    1. Fancy pointer 오버로드: std::pointer_traits<Ptr>::to_address(p) 표현식이 well-formed이면 그 결과를, 아니면 std::to_address(p.operator->())를 돌려줘요.
    1. 원시 포인터 오버로드: T가 함수 타입이면 ill-formed. 아니면 p를 그대로 돌려줘요.

매개변수

  • p: fancy 또는 원시 포인터

반환값

p와 같은 주소를 나타내는 원시 포인터.

가능한 구현

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->());
}

주의 (Notes)

std::to_addressp가 객체가 구성된 저장 공간을 참조하지 않아도 쓸 수 있어요. 그 경우 std::addressof(*p)는 바인딩할 유효한 객체가 없어 쓸 수 없어요. fancy pointer 오버로드는 std::pointer_traits<Ptr> 특수화를 검사하며, 그 특수화 인스턴스화 자체가 ill-formed면 프로그램은 ill-formed예요. std::to_addressstd::contiguous_iterator를 만족하는 반복자에도 쓸 수 있어요.

기능 테스트 매크로는 __cpp_lib_to_address(201711L, C++20)예요.

예제

#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;
}

int main()
{
    std::allocator<int> a;
    auto p = allocator_new(a);
    std::allocator_traits<A>::destroy(a, std::to_address(p));
    a.deallocate(p, 1);
}

더 알아보기 (Learn more)

cppreference