Restore parent from pointer to member

Suppose we have a pointer to a class that points to a class field. We also have a pointer to this particular field in a specific instance of the class. For example, we might have something like this:

class A { B inner_object; } A* myA = /* ... */ B* ptr = &myA->inner_object; BA::* memPtr = &A::inner_object; 

Is there a way to use ptr and memPtr to restore myA ? That is, if we have not yet indicated an explicit pointer to myA , can we make one of ptr and memPtr ?

+7
source share
5 answers

After a decent amount of research ...

This is actually done in most industrial intrusive implementations. However, this requires some hacking.

Strengthening intrusive structures uses the following (and yes, this is a specific implementation)

 template<class Parent, class Member> inline const Parent *parent_from_member(const Member *member, const Member Parent::* ptr_to_member) { return (const Parent*)((const char*)member - offset_from_pointer_to_member(ptr_to_member)); } template<class Parent, class Member> inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) { //The implementation of a pointer to member is compiler dependent. #if defined(BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER) //msvc compliant compilers use their the first 32 bits as offset (even in 64 bit mode) return *(const boost::int32_t*)(void*)&ptr_to_member; //This works with gcc, msvc, ac++, ibmcpp #elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || \ defined(__IBMCPP__) || defined(__DECCXX) const Parent * const parent = 0; const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member)); return std::ptrdiff_t(member - reinterpret_cast<const char*>(parent)); #else //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC return (*(const std::ptrdiff_t*)(void*)&ptr_to_member) - 1; #endif } 

Essentially the same thing (albeit in C), as is done in the linux kernel for managing intrusive lists, with the container_of macro (but, of course, ptr-to-members are not used):

 #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) 
+4
source

Not. A member pointer does not know a single instance of the class of which it is a member. To do this, you need an instance anytime you want to access an element through a pointer.

A pointer to an element is not a pointer. In fact, it was probably a mistake in the C ++ committee part to even call it a pointer. In many (if not most) implementations, even the size of a pointer is not equal to the size of a pointer to a member. There are no biased tricks. And even if you find a way, if you have analyzed the data in a member pointer, it will still be specific to this implementation.

+3
source

You can not.

A pointer to an element does not store information about any particular instance.

It only knows the type and function pointer inside that type.

+1
source

This is definitely not standard and not recommended for actual use, but you can try the following:

 A *fake_A= reinterpret_cast<A *>(1); B *fake_B= &(fake_A->*ptr_to_member); char *fake_A_raw= static_cast<char *>(static_cast<void *>(fake_A)); char *fake_B_raw= static_cast<char *>(static_cast<void *>(fake_B)); ptrdiff_t offset_to_A_from_B= fake_B - fake_A; char *member_raw= static_cast<char *>(static_cast<void *>(member)); char *base_raw= member_raw - offset_to_A_from_B; A *base= static_cast<A *>(static_cast<void *>(base_raw)); 

And you really shouldn't do that.

+1
source

It should be possible and very useful. A pointer to a member is just an offset if you are sure that the structure type contains a pointer to a member.

0
source

All Articles