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 a Data
instance allocated on the heap, and a pointer to its std::string b;
member. How do I get the base address of the Data
instance the string is a member of, taking into account offsets and padding, in a standard way?
I've tried subtracting sizeof(int)
and std::offsetof(Data, std::string)
from the std::string*
pointer, but I couldn't get it to work.
Use offsetof
from <cstddef>
, but beware it is only defined on standard-layout types (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
is detailed in C++11 18.2/4:
The macro
offsetof
(type, member-designator) accepts a restricted set of type arguments in this International Standard. If type is not a standard-layout class (Clause 9), the results are undefined.195 The expressionoffsetof
(type, member-designator) is never type-dependent (14.6.2.2) and it is value-dependent (14.6.2.3) if and only if type is dependent. The result of applying theoffsetof
macro to a field that is a static data member or a function member is undefined. No operation invoked by theoffsetof
macro shall throw an exception andnoexcept(offsetof(type, member-designator))
shall betrue
.
and C99 (N1256) 7.17/3:
The macros are
NULL
which expands to an implementation-defined null pointer constant; and
offsetof(type, member-designator)
which expands to an integer constant expression that has type
size_t
, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that givenstatic type t;
then the expression
&(t.
member-designator)
evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.)
The "restricted set of type arguments in this International Standard" in the C++ standard is there to draw your attention to the fact that offsetof
is more restrictive than is the case for the C standard.