C++:获取包含成员子对象的完整对象的地址

C++: Get adress of complete object containing member subobject

本文关键字:对象 地址 获取 包含 成员 C++      更新时间:2023-10-16

我有两个类,大致定义如下:

class Inner {
public:
bool is_first;
};
class Outer {
public:
char some_other_member;
Inner first;
Inner second;
}

我知道Inner只存在于Outers内部,并且当且仅当相应的对象是first成员而不是second时,相应的布尔标志将设置为true

我正在寻找一种符合标准的方式来派生指向包含某些Inner对象的Outer对象的指针。当然,我可以在每个Inner对象中存储一个指针,但由于Inner类非常小,而且我有很多指针,这似乎是浪费内存(因此是宝贵的缓存(。

显然,编译器应该知道firstsecond和包含Outer对象之间的内存偏移量。问题是:是否有一种符合标准的方法告诉编译器"获取偏移量,从指向Inner的指针中减去它并使其成为Outer指针"?

我知道我可以使用强制转换来voidOuter是否将Inners作为基本子对象(例如这个( - 我非常觉得成员子对象应该可以做类似的事情?

您应该注意,从指向成员的指针获取指向父对象的指针的问题通常是无法解决的。

offsetof和强制转换仅适用于标准布局类型。在其他情况下,它是未定义的行为。

例如,对于多个虚拟继承,它失败。在这种情况下,成员访问是通过比添加编译时偏移量更复杂的方式实现的。也许这实际上并不那么相关,因为它很少使用,但您明确要求符合标准。

没有一个解决方案是严格正确的,你违反了一些指针算术规则。但是,有一个实现定义的解决方案,它几乎总是按照您的期望执行

auto get_outer(Inner& i)
{
return (Inner*)(((uintptr_t)&i) - offsetof(Outer, first));
}

捕获是指针和整数类型转换是实现定义的。

这就是offsetof的用途。

像这样:

Outer *Inner::getOuter() {
size_t offset = flag ? offsetof(Outer, first) : offsetof(Outer, second);
return reinterpret_cast<Outer *>(
reinterpret_cast<char *>(this) - offset);
}

请注意,您reinterpret_casting,因此您完全有责任知道自己在做什么。如果标志不同步,您将获得未定义的行为。

请注意,指针算术只允许在数组中使用,但 §6.9/4 ([basic.types]( 明确表示每个对象都存储在这样的unsigned char数组中:

类型为T的对象的对象表示类型T的对象占用的 N 个unsigned char对象的序列,其中N等于sizeof(T)个。

在此数组中,定义了指针算术。但你需要确保你确实在分配范围内。