How can I reliably get an object's address when operator& is overloaded?

前端 未结 5 1362
野性不改
野性不改 2020-11-27 09:55

Consider the following program:

struct ghost
{
    // ghosts like to pretend that they don\'t exist
    ghost* operator&() const volatile { return 0; }
}         


        
5条回答
  •  失恋的感觉
    2020-11-27 10:09

    The trick behind boost::addressof and the implementation provided by @Luc Danton relies on the magic of the reinterpret_cast; the standard explicitly states at §5.2.10 ¶10 that

    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(x) has the same effect as the conversion *reinterpret_cast(&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.

    Now, this allows us to convert an arbitrary object reference to a char & (with a cv qualification if the reference is cv-qualified), because any pointer can be converted to a (possibly cv-qualified) char *. Now that we have a char &, the operator overloading on the object is no longer relevant, and we can obtain the address with the builtin & operator.

    The boost implementation adds a few steps to work with cv-qualified objects: the first reinterpret_cast is done to const volatile char &, otherwise a plain char & cast wouldn't work for const and/or volatile references (reinterpret_cast cannot remove const). Then the const and volatile is removed with const_cast, the address is taken with &, and a final reinterpet_cast to the "correct" type is done.

    The const_cast is needed to remove the const/volatile that could have been added to non-const/volatile references, but it does not "harm" what was a const/volatile reference in first place, because the final reinterpret_cast will re-add the cv-qualification if it was there in first place (reinterpret_cast cannot remove the const but can add it).

    As for the rest of the code in addressof.hpp, it seems that most of it is for workarounds. The static inline T * f( T * v, int ) seems to be needed only for the Borland compiler, but its presence introduces the need for addr_impl_ref, otherwise pointer types would be caught by this second overload.

    Edit: the various overloads have a different function, see @Matthieu M. excellent answer.

    Well, I'm no longer sure of this either; I should further investigate that code, but now I'm cooking dinner :) , I'll have a look at it later.

提交回复
热议问题