Prev: ADL woes
Next: -1%N = -1
From: xtrigger303 on
Hi to all,

my problem is the following:
let's suppose I have a pointer to an object which I'm sure is enclosed
in another object.
Is it possible (safely) with some pointer arithmetics to get the
address of the enclosing object?
Obviously without passing a "back pointer" to the constructor of the
inner object...

The example below seems to work but I would like some insights from
the experts.

This is just something I would use for a debugging class, in working
code I would certainly
pass a pointer from the enclosing class to the inner object.
Suppose also that I want to use this trick in the CONSTRUCTOR of the
inner object.
At that time the outer object would not be constructed already but the
address I get should be correct,
right?

Thanks very much in advance,
Francesco

P.S.
Sorry for cross-posting to c.l.c++, but I got no answers...


#include <iostream>
#include <cassert>

struct CInner {};
struct COuter
{
char mPad[ 10 ];
CInner mInner;
};


int main()
{
COuter outer;
CInner COuter::* membPtr( &COuter::mInner );
std::cout << &outer << std::endl;
std::cout << &( outer.*membPtr) << std::endl;

// LET'S SUPPOSE I HAVE THE ADDRESS OF THE INNER OBJECT
CInner * innerPtr( &( outer.*membPtr ) );

// NOW I WANT TO GET THE ADDRESS OF THE ENCLOSING OBJECT
// IS THE FOLLOWING OK?
COuter * outerPtr = reinterpret_cast< COuter * >
( innerPtr - &( static_cast< COuter * >( 0 )->*membPtr ) );
std::cout << outerPtr << std::endl;

assert( &outer == outerPtr );
std::cin.get();
}

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Lance Diduck on
On Apr 17, 5:58 am, xtrigger...(a)gmail.com wrote:
> my problem is the following:
> let's suppose I have a pointer to an object which I'm sure is enclosed
> in another object.
> Is it possible (safely) with some pointer arithmetics to get the
> address of the enclosing object?
This is not reliable. This may work for this particular case of a
member in a otherwise plain struct (to maintain C compatibility), but
not in general. For example, add this complexity

struct VOuter:virtual COuter{};
struct VOuter2:virtual VOuter,virtual COuter{};

So given this:
VOuter2 outer;
VOuter2 VOuter2 ::*membPtr( &VOuter2 ::mInner );
how would you find the address of outer from membPtr? It would be
possible to write

COuter * outerPtr = reinterpret_cast< COuter * >
( innerPtr - &( static_cast< COuter * >( 0 )->*membPtr ) );
VOuter2 * vouterPtr=dynamic_cast<VOuter2 >(outerPtr );
however there is no way to determine just when you need that
dynamic_cast, and if you call dynamic_cast on something that has no
virtuals, well that is undefined as well.
Debuggers do use knowledge about object layout to do their work,
however there is no way in general to determine obbject layout using
the syntax of the language only

Lance


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Greg Herlihy on
On Apr 17, 11:01 am, Lance Diduck <lancedid...(a)nyc.rr.com> wrote:
> On Apr 17, 5:58 am, xtrigger...(a)gmail.com wrote:> my problem is the following:
> > let's suppose I have a pointer to an object which I'm sure is enclosed
> > in another object.
> > Is it possible (safely) with some pointer arithmetics to get the
> > address of the enclosing object?
>
> This is not reliable. This may work for this particular case of a
> member in a otherwise plain struct (to maintain C compatibility), but
> not in general.

The "offsetof" macro found in <cstddef> can be applied to any C++ POD-
class reliably - including the COuter class in the original example.
The offsetof macro returns the offset (in bytes) of the member from
its base class pointer:

struct CInner {};
struct COuter
{
char mPad[ 10 ];
CInner mInner;
};

int main()
{
COuter o;
CInner * inner = &o.mInner;

void * v = inner;

v = (static_cast<char*>(v)-offsetof( COuter, mInner));
COuter *outer = static_cast<COuter *>(v);

assert(outer == &o);
}

>For example, add this complexity
>
> struct VOuter:virtual COuter{};
> struct VOuter2:virtual VOuter,virtual COuter{};
> ...

Or refrain from doing so. :-) Since the offsetof macro only works with
POD types, the programmer has to be ensure that COuter is a POD class
before apply offsetof to one of its members. But as long as the class
in question is a POD type, then the offsetof macro - although messy
and inelegant - is the safe solution to the original poster's problem.

Greg


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: courpron on
On Apr 17, 11:58 am, xtrigger...(a)gmail.com wrote:
> Hi to all,
>
> my problem is the following:
> let's suppose I have a pointer to an object which I'm sure is enclosed
> in another object.
> Is it possible (safely) with some pointer arithmetics to get the
> address of the enclosing object?
> Obviously without passing a "back pointer" to the constructor of the
> inner object...
>
> The example below seems to work but I would like some insights from
> the experts.
>
> This is just something I would use for a debugging class, in working
> code I would certainly
> pass a pointer from the enclosing class to the inner object.
> Suppose also that I want to use this trick in the CONSTRUCTOR of the
> inner object.
> At that time the outer object would not be constructed already but the
> address I get should be correct,
> right?
>
> Thanks very much in advance,
> Francesco
>
> P.S.
> Sorry for cross-posting to c.l.c++, but I got no answers...
>
> #include <iostream>
> #include <cassert>
>
> struct CInner {};
> struct COuter
> {
> char mPad[ 10 ];
> CInner mInner;
>
> };
>
> int main()
> {
> COuter outer;
> CInner COuter::* membPtr( &COuter::mInner );
> std::cout << &outer << std::endl;
> std::cout << &( outer.*membPtr) << std::endl;
>
> // LET'S SUPPOSE I HAVE THE ADDRESS OF THE INNER OBJECT
> CInner * innerPtr( &( outer.*membPtr ) );
>
> // NOW I WANT TO GET THE ADDRESS OF THE ENCLOSING OBJECT
> // IS THE FOLLOWING OK?
> COuter * outerPtr = reinterpret_cast< COuter * >
> ( innerPtr - &( static_cast< COuter * >( 0 )->*membPtr ) );
> std::cout << outerPtr << std::endl;
>
> assert( &outer == outerPtr );
> std::cin.get();
>

If COuter is a POD type, it will work. Otherwise it may not work, for
example when multiple and virtual inheritances are involved. By the
way you should better use the (rather unknown) offsetof macro defined
in the <cstddef> header. With the latter, you can replace this :

> COuter * outerPtr = reinterpret_cast< COuter * >
> ( innerPtr - &( static_cast< COuter * >( 0 )->*membPtr ) );

by :

COuter * outerPtr2 = reinterpret_cast< COuter * >
( innerPtr - offsetof(COuter, mInner) );

which is more portable on different architectures. Of course the C++
standard states that the first argument of the offsetof macro shall
accept a POD type.


Alexandre Courpron.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: xtrigger303 on
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! ]

 |  Next  |  Last
Pages: 1 2
Prev: ADL woes
Next: -1%N = -1