Re: Getting address of enclosing object from address of inner object
Thanks a lot to all.
I got Lance point.
But I just want to get the address of the first enclosing object.
I'm not interested in the dynamic type of an object that may have
derived from this "first encloser".
( Hope my english is good enough ).
After your hints I tried to use offsetof but it uses casts to
references instead of pointers, so it gives me some warnings...
PLUS, I do not understand why this technique should not work with non
POD types.
This is my understanding, please correct me if I'm wrong:
1 - First I obtain a "ghost" address of the inner object of a (non-
existent) outer object with address zero.
CInner COuter::* membPtr = &COuter::mInner;
CInner * ghostInnerAddr = &( static_cast< COuter * >( 0 )-
*membPtr );
2 - I calculate the offset in chars
ptrdiff_t offset = reinterpret_cast< char * >( ghostInnerAddr ) -
static_cast< char * >( 0 );
3 - I then subtract from a real inner pointer to obtain the address of
the outer
char * outerAddr = reinterpret_cast< char * >( realInnerAddr ) -
offset;
4 - I cast back to what I'm sure (AM I???) it's the enclosing object
COuter * = reinterpret_cast< COuter * >( outerAddr );
What step can actually go wrong? And why a non-POD type should mess
this up?
Remember I just want to get to the first enclosing object, not to the
address of an object that might have derived from it.
Please check the code below, maybe it's clearer than the
explanation....
I tried with diamond multiple inheritance, non-diamond multiple
inheritance, single inheritance.
It seems to always work...
Thanks again in advance for any comment.
Sorry if I insist but it's just to understand better.
Francesco
#include <cstddef>
#include <cassert>
#include <set>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#define M_DEBUG_TRACKER mDebugTracker
template< typename T >
class CDebugTracker
{
public:
typedef std::set< CDebugTracker< T > const * > CReg;
static CReg sReg;
CDebugTracker() { sReg.insert( this ); }
CDebugTracker( CDebugTracker const & ) { sReg.insert( this ); }
~CDebugTracker() { sReg.erase( this ); }
T const * GetEnclAddr( ) const
{
CDebugTracker< T > const T::* membPtr =
&T::M_DEBUG_TRACKER;
ptrdiff_t offset = reinterpret_cast< char const * >
( &( static_cast< T const * >( 0 )-
*membPtr ) )
- static_cast< char const * >( 0 );
return reinterpret_cast< T const * >(
reinterpret_cast< char const * >( this ) -
offset );
}
};
template< typename T >
std::set< CDebugTracker< T > const * > CDebugTracker< T >::sReg;
#ifndef NDEBUG
#define DEBUG_TRACKER( ENCL_TYPE ) \
template< typename T > friend class CDebugTracker; \
CDebugTracker< ENCL_TYPE > M_DEBUG_TRACKER
#define DEBUG_TRACK_CHECK assert( this ==
M_DEBUG_TRACKER.GetEnclAddr() )
#elif
#define DEBUG_TRACKER( ENCL_TYPE )
#endif
class COuter
{
public:
COuter() { DEBUG_TRACK_CHECK; }
private:
char mPad1[ 5 ];
DEBUG_TRACKER( COuter );
char mPad2[ 5 ];
};
//
class COuter2 : public virtual COuter
{
public:
COuter2() { DEBUG_TRACK_CHECK; }
private:
char mPad1[ 5 ];
DEBUG_TRACKER( COuter2 );
char mPad2[ 5 ];
};
//
class COuter3 : public virtual COuter2, public virtual COuter
{
public:
COuter3() { DEBUG_TRACK_CHECK; }
private:
char mPad1[ 5 ];
DEBUG_TRACKER( COuter3 );
char mPad2[ 5 ];
};
#define INSERT_ADDR( OBJ ) "- " # OBJ << " - " << &OBJ << "\n"
int main()
{
using namespace boost::lambda;
COuter obj1;
COuter2 obj2;
COuter3 obj3;
std::cout << INSERT_ADDR( obj1 ) << std::endl;
std::cout << INSERT_ADDR( obj2 );
std::cout << INSERT_ADDR( static_cast< COuter & >( obj2 ) ) <<
std::endl;
std::cout << INSERT_ADDR( obj3 );
std::cout << INSERT_ADDR( static_cast< COuter2 & >( obj3 ) );
std::cout << INSERT_ADDR( static_cast< COuter & >( obj3 ) ) <<
std::endl;
std::cout << "COuter adrresses:\n";
std::for_each( CDebugTracker< COuter >::sReg.begin(),
CDebugTracker< COuter >::sReg.end(),
std::cout <<
bind( &CDebugTracker< COuter >::GetEnclAddr, _1 )
<< "\n" );
std::cout << "COuter2 adrresses:\n";
std::for_each( CDebugTracker< COuter2 >::sReg.begin(),
CDebugTracker< COuter2 >::sReg.end(),
std::cout <<
bind( &CDebugTracker< COuter2 >::GetEnclAddr, _1 )
<< "\n" );
std::cout << "COuter3 adrresses:\n";
std::for_each( CDebugTracker< COuter3 >::sReg.begin(),
CDebugTracker< COuter3 >::sReg.end(),
std::cout <<
bind( &CDebugTracker< COuter3 >::GetEnclAddr, _1 )
<< "\n" );
std::cin.get();
}
//end
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]