std::addressof(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

✨ NAME ✨

okay so bestie, welcome to std::addressof(3) from the C++ Standard Libary β€” yes, that's the manual name and the whole vibe. And the name itself? It's literally std::addressof β€” iconic, no notes πŸ’….


πŸ“ Synopsis πŸ“

Defined in header <memory>
template< class T >                       (1) (since C++11)
T* addressof( T& arg ) noexcept;              (constexpr since C++17)
template< class T >                       (2) (since C++11)
const T* addressof( const T&& ) = delete;
  1. Obtains the actual address of the object or function arg, even in presence of overloaded operator&. slay.
  2. Rvalue overload is deleted to prevent taking the address of const rvalues. periodt, we are not doing that.

Also, since C++17: the expression std::addressof(e) is a constant subexpression, if e is an lvalue constant subexpression. πŸ¦‹


🌸 Parameters 🌸

  • arg β€” lvalue object or function

πŸŽ€ Return value πŸŽ€

Pointer to arg. simple as that, bestie πŸ’–


🧚 Possible implementation 🧚

The implementation below is not constexpr, because reinterpret_cast is not usable in a constant expression. Compiler support is needed (see below).

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

Correct implementation of this function requires compiler support: GNU libstdc++, LLVM libc++, Microsoft STL. 🫢


πŸ”₯ Notes πŸ”₯

  • Feature-test macro: __cpp_lib_addressof_constexpr β€” value 201603L, std (C++17), feature constexpr std::addressof.

constexpr for addressof is added by LWG2296, and MSVC STL applies the change to C++14 mode as a defect report. iykyk ✨


🌈 Example 🌈

operator& may be overloaded for a pointer wrapper class to obtain a pointer to pointer:

// Run this code

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

πŸ–₯️ Possible output πŸ–₯️

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

πŸ› Defect reports πŸ›

The following behavior-changing defect reports were applied retroactively to previously published C++ standards:

  • LWG 2598 β€” applied to C++11; behavior as published: std::addressof<const T> could take address of rvalues; correct behavior: disallowed by a deleted overload.

πŸ‘‘ See also πŸ‘‘

  • allocator β€” the default allocator (class template)
  • pointer_to [static] β€” obtains a dereferenceable pointer to its argument (public static member function of std::pointer_traits<Ptr>)

and that's the whole page, bestie! πŸ’– source/version/date: http://cppreference.com, 2024.06.10 β€” mwah, bye! 🫢

πŸ“¦ where this page comes from