The standard way to find the base address of a structure from a member

struct Data {
    int a;
    std::string b;
    float c;
};

std::string* allocateDataAndGetString() {
    Data* dataPtr(someAllocator.allocate<Data>());
    return &dataPtr.b;
}

Data* getBaseDataPtrFromString(std::string* mStringMember) {
    // ???
}

int main() {
    std::string* stringPtr(allocateDataAndGetString());
    Data* dataPtr(getBaseDataPtrFromString
}

I have an instance Dataallocated on the heap and a pointer to its member std::string b;. How to get the base address of an instance Datathat is a member, taking into account offsets and indents in a standard way?

I tried to subtract sizeof(int)and std::offsetof(Data, std::string)from the index std::string*, but I could not get it to work.

+2
source share
4 answers

Use offsetoffrom <cstddef>, but be careful, it is determined only by standard types of layouts ( Live at Coliru ):

Data* getBaseDataPtrFromString(std::string* mStringMember) {
    static_assert(std::is_standard_layout<Data>::value,
                  "offsetof() only works on standard-layout types.");
    return reinterpret_cast<Data*>(
      reinterpret_cast<char*>(mStringMember) - offsetof(Data, b)
    );
}

offsetof described in detail in C ++ 11 18.2 / 4:

offsetof (, -) . ( 9), undefined. 195 offsetof (, -) (14.6.2.2 ) (14.6.2.3) , . offsetof , , undefined. , offsetof, , noexcept(offsetof(type, member-designator)) true.

C99 (N1256) 7.17/3:

NULL

, ;

offsetof(type, member-designator)

, size_t, , ( -), ( ), ,

static type t;

&(t. - ) . ( -, undefined.)

" " ++ , offsetof , C.

+5

offsetof , mStringMember char *.

(Data*)((char*)mStringMember - offsetof(Data, b))
+3

offsetof .

, , : static_cast , .

struct Data : private std::string {
private:
    using b_base = std::string;
public:
    // was int f() const { return b.size(); }
    int f() const { return b_base::size(); }

private:
    int a;
    float c;
    friend Data* getBaseDataPtrFromString(std::string* mStringMember);
};

Data* getBaseDataPtrFromString(std::string* mStringMember) {
    return static_cast<Data*>(mStringMember);
}
+2

, ptr s->b ( ), offsetof:

Data* getBaseDataPtrFromString(std::string* ptr) {
   void* ad = (char*)ptr - offsetof(Data,b);
   return reinterpret_cast<Data*>(ad);
}

BTW, GCC has builtin_offsetof to help implement macros offsetof(especially in more general cases than those required by the standard). See this question .

+1
source

Source: https://habr.com/ru/post/1527963/


All Articles