从指向成员的指针恢复父级

发布于 2024-11-27 06:47:09 字数 382 浏览 1 评论 0原文

假设我们有一个指向类成员的指针,指向类的字段。我们还有一个指向该类的特定实例中的特定字段的指针。例如,我们可能有这样的事情:

class A {
     B inner_object;
}

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

有没有办法使用ptrmemPtr来恢复myA?也就是说,如果我们还没有 myA 的显式指针,我们可以用 ptrmemPtr 来创建一个吗?

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

class A {
     B inner_object;
}

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

Is there a way to use ptr and memPtr to recover myA? That is, if we didn't already have an explicit pointer for myA, could we make one out of ptr and memPtr?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

海拔太高太耀眼 2024-12-04 06:47:09

经过大量研究后......

这实际上是在大多数工业侵入列表实现中完成的。然而,它确实需要一些技巧。

Boost侵入式结构使用以下内容(是的,它是特定于实现的)

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

After a decent amount of research...

This is actually done in most industrial intrusive list implementations. It does require some hackery, however.

Boost intrusive structures use the following (and yes, it is implementation specific)

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 to manage 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) );})
陌路黄昏 2024-12-04 06:47:09

你不知道。指向成员的指针不知道它所属的类的任何实例。这就是为什么您在任何时候想要通过指针访问成员时都需要一个实例。

指向成员的指针不是指针。事实上,C++ 委员会将其称为指针可能是一个错误。在许多(如果不是大多数)实现中,甚至指针的大小也不等于指向成员的指针的大小。这里没有你可以玩的抵消技巧。即使您找到了一种方法,如果您解析了指向成员的指针中的数据,它仍然是特定于该实现的。

You don't. A pointer-to-member has no knowledge of any instance of the class that it is a member of. That's why you need an instance anytime you want to access the member through the pointer.

A pointer-to-member is not a pointer. Indeed, it was probably a mistake on the C++ committee's part to even call it a pointer. On many (if not most) implementations, even the sizes of a pointer are not equal to the size of a pointer-to-member. There's no offset tricks you can play here. And even if you found a way, if you parsed the data in a pointer-to-member, it still would be specific to that implementation.

蓝眼泪 2024-12-04 06:47:09

你不能。

指向成员的指针不存储有关任何特定实例的信息。

它只知道一个类型和一个指向该类型内函数的指针。

You can't.

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

It knows only a type, and a pointer to a function within that type.

疾风者 2024-12-04 06:47:09

这绝对不是标准的,也不建议实际使用,但你可以尝试这个:

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

而且你真的不应该这样做。

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

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 this.

起风了 2024-12-04 06:47:09

应该是可以的,而且非常有用。只要您确定什么类型的结构包含指向成员的指针,指向成员的指针只是一个偏移量。

It should be possible and is very useful. Pointer to member is just an offset as long as you are sure of what type of structure contains the pointer to member.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文