7

クラスのフィールドを指しているクラスメンバーへのポインターがあるとします。クラスの特定のインスタンスの特定のフィールドへのポインタもあります。たとえば、次のようなものがあります。

class A {
     B inner_object;
}

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

使用ptrmemPtrて回復する方法はありmyAますか?つまり、 への明示的なポインターがまだない場合、 と からポインターをmyA作成できますか?ptrmemPtr

4

5 に答える 5

4

まともな量の研究の後...

これは、実際にはほとんどの産業用侵入リストの実装で行われます。ただし、ハッカーが必要です。

ブースト侵入型構造は、以下を使用します(もちろん、実装固有です)

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
}

侵入型リストを管理するためにLinuxカーネルでcontainer_ofマクロを使用して行われるのと本質的に同じこと(Cではありますが):(ただし、もちろんptr-to-membersは使用されません):

#define container_of(ptr, type, member) ({ \
            const typeof( ((type *)0)->member ) *__mptr = (ptr); 
            (type *)( (char *)__mptr - offsetof(type,member) );})
于 2011-07-29T21:40:04.677 に答える
3

あなたはそうしない。メンバーへのポインターは、それがメンバーであるクラスのインスタンスを認識しません。そのため、ポインターを介してメンバーにアクセスするときはいつでもインスタンスが必要です。

メンバーへのポインターはポインターではありません。実際、C++ 委員会がそれをポインターと呼んだのはおそらく間違いでした。多くの (ほとんどではないにしても) 実装では、ポインターのサイズでさえ、メンバーへのポインターのサイズと等しくありません。ここでプレイできるオフセット トリックはありません。また、方法を見つけたとしても、メンバーへのポインターでデータを解析した場合でも、その実装に固有のものになります。

于 2011-07-29T01:06:10.983 に答える
1

できません。

メンバーへのポインターは、特定のインスタンスに関する情報を格納しません。

型と、その型内の関数へのポインターのみを認識します。

于 2011-07-29T01:07:12.523 に答える
1

これは間違いなく標準ではなく、実際の使用にはあまりお勧めできませんが、これを試すことができます:

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

そして、あなたは本当にこれをすべきではありません。

于 2011-07-29T01:16:30.997 に答える
0

それは可能なはずであり、非常に便利です。メンバーへのポインターは、メンバーへのポインターを含む構造体のタイプが確実である限り、単なるオフセットです。

于 2015-02-22T20:51:24.963 に答える