Consider the following program:
struct ghost
{
// ghosts like to pretend that they don't exist
ghost* operator&() const volatile { return 0; }
};
int main()
{
ghost clyde;
ghost* clydes_address = &clyde; // darn; that's not clyde's address :'(
}
How do I get clyde
's address?
I'm looking for a solution that will work equally well for all types of objects. A C++03 solution would be nice, but I'm interested in C++11 solutions too. If possible, let's avoid any implementation-specific behavior.
I am aware of C++11's std::addressof
function template, but am not interested in using it here: I'd like to understand how a Standard Library implementor might implement this function template.
In order to get the address of an object, from C++11, the template function std::addressof() should be used instead.
In c++ you can get the memory address of a variable by using the & operator, like: cout << &i << endl; The output of that cout is the memory address of the first byte of the variable i we just created.
There is no way to get the address of a reference. That is because a reference is not an object, it is an alias (this means it is another name for an object).
Use std::addressof
.
You can think of it as doing the following behind the scenes:
Existing implementations (including Boost.Addressof) do exactly that, just taking additional care of const
and volatile
qualification.
Update: in C++11, one may use std::addressof
instead of boost::addressof
.
Let us first copy the code from Boost, minus the compiler work around bits:
template<class T>
struct addr_impl_ref
{
T & v_;
inline addr_impl_ref( T & v ): v_( v ) {}
inline operator T& () const { return v_; }
private:
addr_impl_ref & operator=(const addr_impl_ref &);
};
template<class T>
struct addressof_impl
{
static inline T * f( T & v, long ) {
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}
static inline T * f( T * v, int ) { return v; }
};
template<class T>
T * addressof( T & v ) {
return addressof_impl<T>::f( addr_impl_ref<T>( v ), 0 );
}
What happens if we pass a reference to function ?
Note: addressof
cannot be used with a pointer to function
In C++ if void func();
is declared, then func
is a reference to a function taking no argument and returning no result. This reference to a function can be trivially converted into a pointer to function -- from @Konstantin
: According to 13.3.3.2 both T &
and T *
are indistinguishable for functions. The 1st one is an Identity conversion and the 2nd one is Function-to-Pointer conversion both having "Exact Match" rank (13.3.3.1.1 table 9).
The reference to function pass through addr_impl_ref
, there is an ambiguity in the overload resolution for the choice of f
, which is solved thanks to the dummy argument 0
, which is an int
first and could be promoted to a long
(Integral Conversion).
Thus we simply returns the pointer.
What happens if we pass a type with a conversion operator ?
If the conversion operator yields a T*
then we have an ambiguity: for f(T&,long)
an Integral Promotion is required for the second argument while for f(T*,int)
the conversion operator is called on the first (thanks to @litb)
That's when addr_impl_ref
kicks in. The C++ Standard mandates that a conversion sequence may contain at most one user-defined conversion. By wrapping the type in addr_impl_ref
and forcing the use of a conversion sequence already, we "disable" any conversion operator that the type comes with.
Thus the f(T&,long)
overload is selected (and the Integral Promotion performed).
What happens for any other type ?
Thus the f(T&,long)
overload is selected, because there the type does not match the T*
parameter.
Note: from the remarks in the file regarding Borland compatibility, arrays do not decay to pointers, but are passed by reference.
What happens in this overload ?
We want to avoid applying operator&
to the type, as it may have been overloaded.
The Standard guarantees that reinterpret_cast
may be used for this work (see @Matteo Italia's answer: 5.2.10/10).
Boost adds some niceties with const
and volatile
qualifiers to avoid compiler warnings (and properly use a const_cast
to remove them).
T&
to char const volatile&
const
and volatile
&
operator to take the addressT*
The const
/volatile
juggling is a bit of black magic, but it does simplify the work (rather than providing 4 overloads). Note that since T
is unqualified, if we pass a ghost const&
, then T*
is ghost const*
, thus the qualifiers have not really been lost.
EDIT: the pointer overload is used for pointer to functions, I amended the above explanation somewhat. I still do not understand why it is necessary though.
The following ideone output sums this up, somewhat.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With