views:

74

answers:

4

The following function writes a struct to a file.

#define PAGESIZE  sizeof(BTPAGE)
#define HEADERSIZE 2L

    int btwrite(short rrn, BTPAGE *page_ptr)
    {
        long addr;
        addr = (long) rrn * (long) PAGESIZE + HEADERSIZE;
        lseek(btfd, addr, 0);
        return (write(btfd, page_ptr, PAGESIZE));
    }

The following is the struct.

typedef struct {
    short keycount;             /* number of keys in page   */
    int  key[MAXKEYS];              /* the actual keys      */
    int  value[MAXKEYS];            /* the actual values        */
    short child[MAXKEYS+1];     /* ptrs to rrns of descendants  */
} BTPAGE;

What would happen if I changed the struct to a class, would it still work the same?

If I added class functions, would the size it takes up on disk increase?

+1  A: 

If the class has any virtual function, then you're in trouble; if no virtual functions, you should still be OK (the same applies to a struct, of course, since it, too, could have virtual functions: the difference between struct and class is just that the default visibility in struct is public, in class it's private).

Alex Martelli
+3  A: 

In C++, the difference between a struct and a class is simply that the members and base classes of a struct are public by default, whereas for a class they are private by default.

The technique of simply writing the bytes of the struct to a file and then reading them back in again only works if the struct is a plain old data, or POD, type. If you modify your struct such that it is no longer POD, this technique is not guaranteed to work (the rules describing what makes a POD struct are listed in answers to thet linked question).

James McNellis
A: 

If you are doing more serialisation of classes consider using google protocol buffers, or something similar see this question

Harald Scheirich
+4  A: 

Boy oh boy. There's a lot you need to learn here.

  • First of all, you're treating a structure as an array of bytes. This is strictly undefined behavior due to the strict aliasing rule. Anything can happen. So don't do it. Use proper serialization (for example via boost) instead. Yes, it's tedious. Yes, it's necessary.
  • Even if you ignore the undefinedness, and choose to become dependant on some particular compiler implementation (which may change even in the next compiler version), there's still reasons not to do it.
    • If you save a file on one machine, then load it on another, you may get garbage, because the second machine uses a different float representation, or a different endianness, or has different alignment rules, etc.
    • If your struct contains any pointers, it's very likely that saving them verbatim then loading them back will result in an address that doesn't not point to any meaningful place.
  • Typically when you add a member function, this happens:
    • the function's machine code is stored in a place shared by all the class instances (it wouldn't make sense to duplicate it, since it's logically immutable)
    • a hidden "this" pointer is passed to the function when it's called, so it knows which object it's been called on.
    • none of this requires any storage space in the instances.
  • However, when you add at least one virtual function, the compiler typically needs to also add a data chunk called a vtable (read up on it). This makes it possible to call different code depending on the current runtime type of the object (aka polymorphism). So the first virtual function you add to the class likely does increase the object size.
Stefan Monov
Concerning strict aliasing, it is permitted to treat any POD-type object as an array of bytes. Any type of object may be accessed via a `char*`, and copying the bytes composing a POD-type object into an array of char and then copying those bytes back into an object of the same POD-type is well-defined. (The points you make about unportability are still valid, of course).
James McNellis