Alex Rivera | Logout

Looking for something similar to offsetof() for non-POD types

Asked 2008-10-07T10:33:54.177
11

I'm looking for a way to obtain offsets of data members of a C++ class which is of non-POD nature.

Here's why:

I'd like to store data in HDF5 format, which seems most suited for my kind of material (numerical simulation output), but it is perhaps a rather C-oriented library. I want to use it through the C++ interface, which would require me to declare storage types like so (following documentation from here and here (section 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

where HOFFSET is a HDF-specific macro that uses offsetof.

The problem is of course, that as soon as the example-class becomes it little bit more featureful, it is no longer of POD-type, and so using offsetof will give undefined results.

The only workaround I can think of is to first export the data I want to store to a simpler struct, then pass that to HDF. That does however involve data copying, which is exactly what HDF is trying to avoid (and why they have this CompType which enables the library to reach into your objects to save their data to file).

So I was hoping you'd have better ideas. Ideally I'd be looking for a portable workaround for this problem, but if short of that you could give me an idea that works on x86 and x86_64 with GCC I'd already be immensely grateful.

----- appended later: -----

Greg

Edit
Report

3 Answers

3

You could declare the POD types in a base class, then extend that class (perhaps with private inheritance) to add your additional functionality.

Update to your update: Because an instance of derived_non_pod can also be treated as a base_pod, therefore the offsets to data members must be the same. With regard to implementation, your compiler will allocate the vtable pointer after the fields of the base_pod when laying out the derived_non_pod structure.

It occurs to me that if you use private inheritance, the compiler may be able to choose to reorder the data fields. It's unlikely to do so, however, and making the inheritance protected or public would avoid this possible trap.

answered 2008-10-07T10:36:23.190
1

I'm pretty sure that Roel's answer along with consideration for onebyone's answer covers most of what you ask.

struct A
{
  int i;
};

class B: public A
{
public:
  virtual void foo ()
  {
  }
};

int main ()
{
  std::cout << offsetof (B, A::i) << std::endl;
}

With g++, the above outputs 4, which is what you'd expect if B has a vtable before the base class member 'i'.

It should be possible though to calculate the offset manually, even for the case where there are virtual bases:

struct A1 {
  int i;
};

struct A2 {
  int j;
};

struct A3 : public virtual A2 {
};

class B: public A1, public A3 {
public:
  virtual void foo () {
  }
};

template <typename MostDerived, typename C, typename M>
ptrdiff_t calcOffset (M C::* member)
{
  MostDerived d;
  return reinterpret_cast<char*> (&(d.*member)) - reinterpret_cast<char*> (&d);
}

int main ()
{
  B b;
  std::cout << calcOffset<B> (&A2::j) << ", " 
            << calcOffset<B> (&A1::i) << std::endl;
}

With g++, this program outputs 4 and 8. Again this is consistent with the vtable as the first member of B followed by the virtual base A2 and its member 'j'. Finally the non virtual base A1 and its member 'i'.

The key point is that you always calculate the offsets based on the most derived object, ie. B. If the members are private then you may need to add a "getMyOffset" call for each member. This call will perform the calculation where the name is accessible.

You might find the following useful too. I think it's nice to associate all of this with the object that you're building the HDF ty

answered 2009-08-05T18:02:28.567
0

Would using a pointer to member work instead of offsetof()? I know that you'd probably have to do all sorts of casting to be able to actually use the pointer since I'm guessing that InsertMember is acting on the type specified in the last parameter at runtime.

But with your current solution you're already going around the type system so I'm not sure that your losing anything there. Except that the syntax for pointers to member is hideous.

answered 2008-10-07T17:34:23.393

Your Answer