Search code examples
c++pointersmember-pointers

Get pointer to enclosing instance from member pointer


I have a custom class with some data members. I've got a pointer to one of the class' data member, and I would like to have a pointer to its enclosing instance. For example:

class MyClass{
public:
    int a;
    int b;
    virtual ~MyClass(){//because MyClass is not POD type
    }
};

...

int* aptr = ...; //something valid, and i know its a pointer to a MyClass::a member
MyClass* classptr = ?; //how can i get a pointer to the class instance?

The class is not a POD type, so the offsetof macro doesn't always work/it gives a compile warning.

Is it possible to get a pointer to the MyClass instance?


Solution

  • You cannot do this using well-defined C++ as casting between unrelated types is undefined behaviour.

    In reality, you'll probably get away with assuming that the address of the first member of a class is the same as the address of the class offset by the size of a pointer on your system. (This pointer being the implementation of your v-table and that's reasonably consistent across C++ implementations.) Then, if you make some assumptions about the packing of the data members, then you make manual adjustments to your pointer to move from one data member to another. offsetof is another technique and can help you here, but it's still not well-defined in your context.

    Either litter your source code with specific compiler assertions (as you are restricting portability), or adopt a different technique. I'd certainly adopt the latter.

    Here's some very bad code which shows you how to do it. Consider

    struct Foo
    {
        virtual ~Foo(){}; /*introduce a v-table*/
        int n;
    };
    

    And,

      Foo foo;
      foo.n = 0xdeadbeef; // To test
      int* p = &foo.n; // Suppose this is our pointer.
      char* pp = (char*)(void*)p; // This cast is undefined behaviour.
      pp -= 8; // Skip over 64 bit v-table. More undefined behaviour.
      Foo* ph = (Foo*)(pp); // Yet more undefined behaviour.
    

    ph points to a Foo instance.