Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++14

I have two classes, roughly defined like this:

class Inner {
public:
  bool is_first;
};

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

I known that Inners only ever live inside Outers, and that the respective bool flag will be set to true if and only if the respective object is the first member, not the second.

I am looking for a standard-compliant way of deriving a pointer to the Outer object containing some Inner object. Of course I could just store a pointer inside every Inner object, but since the Inner class is very small and I have lots of them, that seems like a waste of memory (and thus precious cache).

Obviously, the compiler should know the memory offset between first, second and the containing Outer object. The question is: Is there a standard-compliant way of telling the compiler "get that offset, subtract it from the pointer to Inner and make it an Outer pointer"?

I know I could use casting to void if Outer would contain the Inners as base subobjects (e.g. this) - I very much feel like something similar should be possible for member subobjects?

like image 467
Lukas Barth Avatar asked Sep 12 '25 18:09

Lukas Barth


2 Answers

You should note that the problem of obtaining the pointer to a parent object from a pointer to a member is generally not solvable.

The offsetof and casting only works for standard layout types. In the other cases it is undefined behavior.

It fails for instance for multiple virtual inheritance. In that case member access is implemented through a more complicated way than adding a compile time offset. Perhaps this is practically not so relevant as it is very rarely used, but you explicitly asked for standard compliance.

like image 109
Andreas H. Avatar answered Sep 15 '25 09:09

Andreas H.


No solution is strictly correct, you run afoul some pointer arithmetic rules. However, there is an implementation-defined solution, which almost always does what you expect it to

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

The catch being pointer and integral type conversions are implementation defined.

like image 36
Passer By Avatar answered Sep 15 '25 08:09

Passer By