Spec-Zone.ru › C++

std::to_address

Определено в заголовке <memory>
template< class Ptr >
constexpr auto to_address( const Ptr& p ) noexcept;
(1) (начиная с C++20)
template< class T >
constexpr T* to_address( T* p ) noexcept;
(2) (начиная с C++20)

Получает адрес, представленный p, не создавая ссылку на объект, на который указывает p.

1) Перегрузка для расширенных указателей: если выражение std::pointer_traits<Ptr>::to_address(p) корректно, возвращает результат этого выражения. В противном случае возвращает std::to_address(p.operator->()).
2) Перегрузка для обычных указателей: если T имеет функциональный тип, программа некорректна. В противном случае возвращает p без изменений.

Параметры

p - расширенный или обычный указатель

Возвращаемое значение

Обычный указатель, представляющий тот же адрес, что и 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->());
}

Примечания

std::to_address можно использовать, даже если p не указывает на область памяти, в которой создан объект. В этом случае std::addressof(*p) использовать нельзя, поскольку нет допустимого объекта, к которому можно привязать параметр std::addressof.

Перегрузка std::to_address для расширенных указателей проверяет специализацию std::pointer_traits<Ptr>. Если инстанцирование этой специализации некорректно (обычно потому, что element_type нельзя определить), это приводит к безусловной ошибке вне непосредственного контекста и делает программу некорректной.

std::to_address также можно использовать с итераторами, удовлетворяющими требованиям std::contiguous_iterator.

Макрос проверки поддержки возможностей Значение Стандарт Возможность
__cpp_lib_to_address 201711L (C++20) Средство для преобразования указателя в обычный указатель (std::to_address)

Пример

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

См. также

pointer_traits
(C++11)
предоставляет информацию о типах, подобных указателям
(шаблон класса)
to_address
[статический] (C++20)(необязательно)
получает обычный указатель из расширенного указателя (обратная операция для pointer_to)
(открытая статическая функция-член std::pointer_traits<Ptr>)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/memory/to_address

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API