从成员中查找struct的基址的标准方法

Vit*_*meo 2 c++ struct offsetof memory-address c++11

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
}
Run Code Online (Sandbox Code Playgroud)

Data在堆上分配了一个实例,并指向了它的std::string b;成员.如何Data以标准方式获取字符串所属实例的基址,并考虑偏移和填充?

我试过减sizeof(int)std::offsetof(Data, std::string)std::string*指针,但我无法得到它的工作.

Cas*_*sey 5

使用offsetof<cstddef>,但要注意它只能是在标准布局类型(指住在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)
    );
}
Run Code Online (Sandbox Code Playgroud)

offsetof 详见C++ 11 18.2/4:

offsetof(类型,成员指示符)在此国际标准中接受一组受限制的类型参数.如果type不是标准布局类(第9节),则结果是未定义的.195表达式offsetof(类型,成员指示符)从不依赖于类型(14.6.2.2),并且当且仅当类型依赖时,它才是值依赖的(14.6.2.3).将offsetof宏应用于作为静态数据成员或函数成员的字段的结果是未定义的.offsetof宏调用的任何操作都不应抛出异常,并且noexcept(offsetof(type, member-designator))应该是true.

和C99(N1256)7.17/3:

宏是

NULL
Run Code Online (Sandbox Code Playgroud)

它扩展为实现定义的空指针常量; 和

offsetof(type, member-designator)
Run Code Online (Sandbox Code Playgroud)

它从结构的开头(由类型指定)扩展为一个整数常量表达式size_t,该表达式的类型(其值是以字节为单位的偏移量)到结构成员(由member-designator指定).类型和成员指示符应为给定的

static type t;
Run Code Online (Sandbox Code Playgroud)

然后表达式&(t.member-designator)求值为地址常量.(如果指定的成员是位字段,则行为未定义.)

C++标准中的"本国际标准中的限制类型参数"是引起您注意的事实,offsetof它比C标准的情况更具限制性.