Восстановить родителя от указателя на член - PullRequest
7 голосов
/ 29 июля 2011

Предположим, что у нас есть член указатель на класс, указывающий на поле класса.У нас также есть указатель на это конкретное поле в конкретном экземпляре класса.Например, у нас может быть что-то вроде этого:

class A {
     B inner_object;
}

A* myA = /* ... */
B* ptr = &myA->inner_object;
B A::* memPtr = &A::inner_object;

Есть ли способ использовать ptr и memPtr для восстановления myA?То есть, если у нас еще не было явного указателя для myA, мы могли бы сделать один из ptr и memPtr?

Ответы [ 5 ]

4 голосов
/ 30 июля 2011

После приличного количества исследований ...

На самом деле это делается в большинстве промышленных реализаций списков. Однако это требует некоторой взлома.

Повысить навязчивые структуры используют следующее (и да, это зависит от реализации)

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
}

По существу то же самое (хотя и в C), что и в ядре linux для управления навязчивыми списками, с помощью контейнера container_of (но, конечно, ptr-to-members не используются):

#define container_of(ptr, type, member) ({ \
            const typeof( ((type *)0)->member ) *__mptr = (ptr); 
            (type *)( (char *)__mptr - offsetof(type,member) );})
3 голосов
/ 29 июля 2011

Ты не. Указатель на член не знает ни одного экземпляра класса, членом которого он является. Вот почему вам нужен экземпляр в любое время, когда вы хотите получить доступ к члену через указатель.

Указатель на элемент не указатель. Действительно, со стороны комитета C ++ было, вероятно, ошибкой даже называть это указателем. Во многих (если не в большинстве) реализациях даже размеры указателя не равны размеру указателя на член. Там нет смещения трюки, которые вы можете играть здесь. И даже если вы нашли способ, если вы проанализировали данные в указателе на член, он все равно будет специфичным для этой реализации.

1 голос
/ 29 июля 2011

Это определенно не стандарт и не рекомендуется для реального использования, но вы можете попробовать это:

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));

И ты действительно не должен этого делать.

1 голос
/ 29 июля 2011

Вы не можете.

Указатель на член не хранит информацию о каком-либо конкретном экземпляре.

Он знает только тип и указатель на функцию внутри этого типа.

0 голосов
/ 22 февраля 2015

Это должно быть возможно и очень полезно. Указатель на член - это просто смещение, если вы уверены, что тип структуры содержит указатель на член.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...