我正在寻找一种方法来获得非POD性质的C++类数据成员的偏移量.
原因如下:
我想以HDF5格式存储数据,这似乎最适合我的材料(数值模拟输出),但它可能是一个相当C的库.我想通过C++接口来使用它,这需要我申报存储类型像这样,(从文件在这里和这里(第4.3.2.1.1)):
class example { public: double member_a; int member_b; } //class example H5::CompType func_that_creates_example_CompType() { H5::CompType ct; ct.insertMember("a", HOFFSET(example, member_a), H5::PredType::NATIVE_DOUBLE); ct.insertMember("b", HOFFSET(example, member_b), H5::PredType::NATIVE_INT); return ct; } //func_that_creates_example_CompType
其中HOFFSET是使用offsetof的HDF特定宏.
问题当然是,只要示例类变得更有用,它就不再是POD类型,因此使用offsetof将给出不确定的结果.
我能想到的唯一解决方法是首先将我想要存储的数据导出到更简单的结构,然后将其传递给HDF.然而,这确实涉及数据复制,这正是HDF试图避免的(以及为什么他们有这个CompType使得库能够到达你的对象以将他们的数据保存到文件中).
所以我希望你有更好的想法.理想情况下,我会为这个问题寻找一个可移植的解决方法,但如果没有,你可以给我一个适用于x86和x86_64与GCC的想法,我已经非常感激了.
-----后来添加:-----
Greg Hewgill建议在下面将数据存储在一个简单的结构中,然后通过继承来构建实际的类.特别是对于HDF,我认为这可能实际上不起作用.比上面更精细的使用场景:
class base_pod { public: double member_a; int member_b; }; //class base_pod class derived_non_pod : private base_pod { public: //the following method is only virtual to illustrate the problem virtual double get_member_a() {return member_a; } }; //class derived_non_pod class that_uses_derived_non_pod { public: void whatever(); private: derived_non_pod member_c; }; //class that_uses_derived_non_pod
现在,当我们存储类that_uses_derived_non_pod的实例时,我们无法将其内存布局描述为具有base_pod作为member_c.这会导致偏移错误,因为derived_non_pod会添加时髦的东西(比如虚拟函数表,我猜?).
Greg Hewgill的解决方案可能比这更好(可能是组合而不是继承).
但是,我认为对于x86和x86_64上的GCC,即使对于非POD类型的成员,offsetof实际上也会起作用,只要它"有意义".因此,例如,它不适用于从虚拟基类继承的成员,因为在GCC中使用额外的间接实现.但是只要你坚持普通的公共单继承,GCC恰好会以一种方式布置你的对象,这意味着每个成员都可以在偏离对象指针的位置访问,因此offsetof实现将给出正确的答案.
当然麻烦的是你必须忽略警告,这意味着如果你做了一些不起作用的事情,你将取消引用一个接近空的指针.从好的方面来说,问题的原因可能在运行时很明显.在负面,eeew.
[编辑:我刚刚在gcc 3.4.4上对此进行了测试,实际上在获取从虚拟基类继承的成员的偏移量时,警告会升级为错误.这很好.我仍然有点担心gcc的未来版本(4,甚至,我没有提到)会更严格,如果采用这种方法,你的代码可能在将来停止编译.