反转指向成员的指针(即获取包含结构的地址)

Invert pointer to member (i.e. get the address of the containing struct)

本文关键字:获取 包含 结构 地址 指针 成员      更新时间:2023-10-16

我有一个结构(Member),它只能用作其他结构(Container)中的数据成员。按照惯例,成员的名称总是m。有没有可靠的方法让成员获得包含结构的地址?

template<typename Struct>
struct Member;
{
  const Struct& s = ??;
                    // this - &Struct::m
};
struct Container
{
   Member<Container> m;
};

我希望使用指向成员&Container::m的指针可能有助于从成员对象本身的地址进行计算?

不,您不能这样做。您可以确定Containerm的偏移量,并进行指针运算来猜测Container的结果地址,但这将是:

  • 不可靠的
  • 容易出现灾难性错误
  • UB(因此可能导致包括时间旅行在内的症状,不,严重!)

如果您禁用了所有优化,它可能会在一些平台上持续运行,但实际上,请不要这样做。

将指向Container的指针/引用传递到Member<Container>的构造函数中(添加一个之后),或者进一步重新考虑您的设计。为什么成员需要知道封装它的对象?这几乎总是错误的(尽管有一些可以通过的用例)。

不确定"可靠",这是不应该鼓励的黑客行为,但以下应该给你一个很好的起点:

#include <cassert>
#include <cstddef>
#include <type_traits>
template<typename Struct>
struct Member
{
    Struct const* s = (Struct*)&((char*)this)[-(int)offsetof(Struct, m)];
};
struct Container
{
    int abc;
    int def;
    Member<Container> m;
};

int main(int argc, char* argv[])
{
    assert(std::is_standard_layout<Container>::value);
    Container c;
    Container const *p1 = &c;
    Container const *p2 = c.m.s;
    bool test = p1 == p2;
    return 0;
}

我添加了一些成员,以便m有一个实际的非零偏移量进行测试,但它也适用于零偏移量。