Spec-Zone.ru › C++

std::addressof

Определено в заголовочном файле <memory>
template< class T >
T* addressof( T& arg ) noexcept;
(1) (начиная с C++11)
(constexpr начиная с C++17)
template< class T >
const T* addressof( const T&& ) = delete;
(2) (начиная с C++11)
1) Получает фактический адрес объекта или функции arg, даже если operator& перегружен.
2) Перегрузка для rvalue удалена, чтобы запретить получение адреса const rvalue.

Выражение std::addressof(e) является постоянным подвыражением, если e является постоянным подвыражением категории lvalue.

(начиная с C++17)

Параметры

arg - объект или функция категории lvalue

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

Указатель на arg.

Возможная реализация

Приведённая ниже реализация не является constexpr, поскольку reinterpret_cast нельзя использовать в постоянном выражении. Требуется поддержка компилятора (см. ниже).

template<class T>
typename std::enable_if<std::is_object<T>::value, T*>::type addressof(T& arg) noexcept
{
    return reinterpret_cast<T*>(
               &const_cast<char&>(
                   reinterpret_cast<const volatile char&>(arg)));
}

template<class T>
typename std::enable_if<!std::is_object<T>::value, T*>::type addressof(T& arg) noexcept
{
    return &arg;
}

Для корректной реализации этой функции требуется поддержка компилятора: GNU libstdc++, LLVM libc++, Microsoft STL.

Примечания

Макрос проверки функциональности Значение Стандарт Функция
__cpp_lib_addressof_constexpr 201603L (C++17) constexpr std::addressof

constexpr для addressof добавлен предложением LWG2296, а MSVC STL применяет это изменение в режиме C++14 как отчёт об ошибке.

В некоторых необычных случаях использование встроенного operator& некорректно из-за поиска, зависящего от аргументов, даже если оно не перегружено; вместо него можно использовать std::addressof.

template<class T>
struct holder { T t; };

struct incomp;

int main()
{
    holder<holder<incomp>*> x{};
    // &x; // error: argument-dependent lookup attempts to instantiate holder<incomp>
    std::addressof(x); // OK
}

Пример

operator& можно перегрузить для класса-обёртки указателя, чтобы получить указатель на указатель:

#include <iostream>
#include <memory>

template<class T>
struct Ptr
{
    T* pad; // add pad to show difference between 'this' and 'data'
    T* data;
    Ptr(T* arg) : pad(nullptr), data(arg)
    {
        std::cout << "Ctor this = " << this << '\n';
    }

    ~Ptr() { delete data; }
    T** operator&() { return &data; }
};

template<class T>
void f(Ptr<T>* p)
{
    std::cout << "Ptr   overload called with p = " << p << '\n';
}

void f(int** p)
{
    std::cout << "int** overload called with p = " << p << '\n';
}

int main()
{
    Ptr<int> p(new int(42));
    f(&p);                // calls int** overload
    f(std::addressof(p)); // calls Ptr<int>* overload, (= this)
}

Возможный вывод:

Ctor this = 0x7fff59ae6e88
int** overload called with p = 0x7fff59ae6e90
Ptr   overload called with p = 0x7fff59ae6e88

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

DR Применён к Опубликованное поведение Корректное поведение
LWG 2598 C++11 std::addressof<const T> мог получать адрес rvalue запрещено удалённой перегрузкой

См. также

allocator
аллокатор по умолчанию
(шаблон класса)
pointer_to
[static]
получает разыменовываемый указатель на свой аргумент
(общедоступная статическая функция-член std::pointer_traits<Ptr>)

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

Spec-Zone.ru

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