addressof函数

addressof()的实现原理,实际是一个cast trick,c++标准中有如下的规定:

An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer
to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a
reference cast reinterpret_cast<T&>(x) has the same effect as the conversion
reinterpret_cast<T>(&x) with the built-in & and * operators. The result is an lvalue that refers
to the same object as the source lvalue, but with a different type. No temporary is created, no copy is made,
and constructors (12.1) or conversion functions (12.3) are not called.67) (ISO/IEC 14882:2003(E) 5.2.10 Reinterpret cast)

大体意思就是如果一个指向T1类型的指针可以通过reinterpret_cast明确的转换成一个指向T2类型的指针,那么类型为T1的左值表达式就可以强制转化成一个T2类型的引用,也就是说cast reinterpret_cast<T&>(x)和reinterpret_cast<T>(&x)是等价的,前提是在内建&和语意下。c++
标准还强调,上述的转换结果是一个左值,和被转换的源左值引用着同一个对象,只是类型不同而已,也就是说c++标准保证,如果一个T1类型的对象x,被强制转换成了一个T2类型引用,那么T2引用是引用着T1对象,想当于
reinterpret_cast<T2*>(&x) 。
所以说addressof()函数的实现是基于上述规定的。

#include "addressof.hpp"
#include <iostream>
#include <memory> // std::addressof

// Blog: http://blog.csdn.net/fengbingchun/article/details/70406274

////////////////////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/memory/addressof
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 << std::endl;
    }

    ~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 test_addressof_1()
{
    Ptr<int> p(new int(42));
    f(&p);                 // calls int** overload
    f(std::addressof(p));  // calls Ptr<int>* overload, (= this)

    return 0;
}

////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/memory/addressof/
struct unreferenceable {
    int x;
    unreferenceable* operator&() { return nullptr; }
};

void print(unreferenceable* m) {
    if (m) std::cout << m->x << '\n';
    else std::cout << "[null pointer]\n";
}

int test_addressof_2()
{
    void(*pfn)(unreferenceable*) = &print; // void(*pfn)(unreferenceable*); pfn = &print;

    unreferenceable val{ 10 };
    unreferenceable* foo = &val;
    unreferenceable* bar = std::addressof(val);

    (*pfn)(foo);   // prints [null pointer]
    (*pfn)(bar);   // prints 10

    return 0;
}

/////////////////////////////////////////////////////////
// reference: http://cppisland.com/?p=414
class Buffer
{
private:
    static const size_t buffer_size = 256;
    int bufferId;
    char buffer[buffer_size];

public:
    Buffer(int bufferId_) : bufferId(bufferId_) {}
    Buffer* operator&() { return reinterpret_cast<Buffer*> (&buffer); }  //BAD practice, only for illustration!
};

template<typename T>
void getAddress(T t)
{
    std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
    std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

int test_addressof_3()
{
    int a = 3;
    fprintf(stderr, "a &: %p, address of: %p\n", &a, std::addressof(a));

    Buffer b(1);
    std::cout << "Getting the address of a Buffer type: \n";
    getAddress(b);

    return 0;
}

/////////////////////////////////////////////////////////
// reference: https://wizardforcel.gitbooks.io/beyond-stl/content/38.html
class codebreaker {
public:
    int operator&() const {
        return 13;
    }
};

int test_addressof_4()
{
    codebreaker c;

    std::cout << "&c: " << (&c) << '\n';
    std::cout << "addressof(t): " << std::addressof(c) << '\n';

    return 0;
}

推荐阅读更多精彩内容