您的位置:首页 > 移动开发 > Objective-C

boost中模板函数addressof()实现原理

2010-04-04 23:12 357 查看
&作为取址符号用来获取对象的地址,但由于c++太灵活,通过重载operator&可以改变operator&原有的语意。

如下代码:

 
#include <iostream>
using namespace std;
class Object
{
public:
int operator&()
{
return 0;
}
};
int main()
{
Object obj;
cout<<&obj<<endl;//输出诡异的0
system("pause");
}


 

虽然c++支持对operator&的重载,但绝大部分情况下我们无论如何也不应该重载operator&,但是不乏不怀好意的人来重载operator&,

当你需要使用对象的真实地址时,这种情况下boost库中addressof函数满足我们的需求了:

#include <iostream>
#include <boost/utility.hpp>
using namespace boost;
using namespace std;
class Object
{
public:
int i;
Object():i(0x11223344){}
int operator&()
{
return 0;
}

};
int main()
{
Object obj;
cout<<&obj<<endl;//输出0

Object *p=addressof(obj);
cout<<p<<endl;//输出obj真实地址
cout<<hex<<p->i<<endl;//验证一下,通过这个地址确实可以访问的到i,确实是0x11223344
system("pause");
}


神奇吧~~~没有做不到,只有想不到这句话比较适合c++滴~~~~~

现在我们要关注一下,这个addressof函数的实现原理是啥啊,来看下源码先:

  
namespace boost
{

namespace detail
{

template<class T> struct addr_impl_ref
{
T & v_;

inline addr_impl_ref( T & v ): v_( v ) {}
inline operator T& () const { return v_; }
};

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)));
//这是关键的地方,先强制转换成const volatile char &,然后去掉const属性,再取址,避免调用v的重载的operator&
}

static inline T * f( T * v, int )
{
return v;
}
};

} // namespace detail

template<class T> T * addressof( T & v )
{
#if defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x610 ) )

return boost::detail::addressof_impl<T>::f( v, 0 );

#else

return boost::detail::addressof_impl<T>::f( boost::detail::addr_impl_ref<T>( v ), 0 );//vc平台走这个分支,
//调用addr_impl_ref<T>的构造函数创建一个addr_impl_ref<T>对象,
//由于boost::detail::addressof_impl<T>::f( T & v, long ),所以
//addr_impl_ref<T>对象要被强制转换成T&,触发addr_impl_ref重载的
//T& (),最终返回v的引用。

#endif
}

#endif // BOOST_UTILITY_ADDRESSOF_HPP


以上是模板函数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()函数的实现是基于上述规定的。

所以

Object *p=(Object*)&(char&)obj;


c++保证也会返回obj的真实地址的。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息