I'm confused about the space a class takes in a structure?

Discussion in 'C++' started by Pep, Aug 17, 2007.

  1. Pep

    Pep Guest

    I'm getting weird results at the moment so thought I'd rebase my
    knowledge of c++ storage with your help :)

    I have a class used as a type in a struct and the struct is handled by
    a 3rd party binary writed for persistent storage. I am confused by the
    results I am getting and am not sure how the 3rd party writer is
    seeing the size of the stuct.

    class foo
    // I have not included the methods for brevity
    {
    public:
    unsigned short shortArray[4];
    };

    typedef struct
    {
    foo fooVar;
    char charArray[8];
    } bar;

    So if you do a sizeof(foo) you get back 8 as a result and a
    sizeof(bar) returns 16. However the class foo has methods as well. Now
    if I was to do any form of binary copy on bar such as using memcpy for
    example using the sizeof(bar) as the length, will I definitely be
    copying the complete data in bar or will the operation be thrown out
    by things like internal members in foo created by the compiler, like
    the vtbl in foo?

    TIA :)
     
    Pep, Aug 17, 2007
    #1
    1. Advertising

  2. * Pep:
    > I'm getting weird results at the moment so thought I'd rebase my
    > knowledge of c++ storage with your help :)
    >
    > I have a class used as a type in a struct and the struct is handled by
    > a 3rd party binary writed for persistent storage. I am confused by the
    > results I am getting and am not sure how the 3rd party writer is
    > seeing the size of the stuct.
    >
    > class foo
    > // I have not included the methods for brevity
    > {
    > public:
    > unsigned short shortArray[4];
    > };
    >
    > typedef struct
    > {
    > foo fooVar;
    > char charArray[8];
    > } bar;
    >
    > So if you do a sizeof(foo) you get back 8 as a result and a
    > sizeof(bar) returns 16. However the class foo has methods as well. Now
    > if I was to do any form of binary copy on bar such as using memcpy for
    > example using the sizeof(bar) as the length, will I definitely be
    > copying the complete data in bar or will the operation be thrown out
    > by things like internal members in foo created by the compiler, like
    > the vtbl in foo?
    >
    > TIA :)


    Binary level copying is ungood for serializing pointer values (do you
    understand why?), and hence also for instances of a class with one or
    more virtual member functions (hence, in practice, vtable pointer).

    Use some other method of serialization; this is discussed at length in
    the FAQ, although not as clearly as I'd wished.

    And in general, don't use memcpy etc., and more importantly, to avoid a
    lot of such problems, simply stop thinking about micro-optimizations:
    they're evil evil evil. An incorrect program can be as fast as you want
    since it doesn't need to do anything, but generally that's not what you
    ultimately want. So, think first correctness, not micro-optimization.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Aug 17, 2007
    #2
    1. Advertising

  3. Pep

    Pep Guest

    Alf P. Steinbach wrote:
    > * Pep:
    > > I'm getting weird results at the moment so thought I'd rebase my
    > > knowledge of c++ storage with your help :)
    > >
    > > I have a class used as a type in a struct and the struct is handled by
    > > a 3rd party binary writed for persistent storage. I am confused by the
    > > results I am getting and am not sure how the 3rd party writer is
    > > seeing the size of the stuct.
    > >
    > > class foo
    > > // I have not included the methods for brevity
    > > {
    > > public:
    > > unsigned short shortArray[4];
    > > };
    > >
    > > typedef struct
    > > {
    > > foo fooVar;
    > > char charArray[8];
    > > } bar;
    > >
    > > So if you do a sizeof(foo) you get back 8 as a result and a
    > > sizeof(bar) returns 16. However the class foo has methods as well. Now
    > > if I was to do any form of binary copy on bar such as using memcpy for
    > > example using the sizeof(bar) as the length, will I definitely be
    > > copying the complete data in bar or will the operation be thrown out
    > > by things like internal members in foo created by the compiler, like
    > > the vtbl in foo?
    > >
    > > TIA :)

    >
    > Binary level copying is ungood for serializing pointer values (do you
    > understand why?), and hence also for instances of a class with one or
    > more virtual member functions (hence, in practice, vtable pointer).
    >


    I agree but as I said, the binary copying is being done by a 3rd party
    database which I have no control over.

    > Use some other method of serialization; this is discussed at length in
    > the FAQ, although not as clearly as I'd wished.
    >
    > And in general, don't use memcpy etc., and more importantly, to avoid a
    > lot of such problems, simply stop thinking about micro-optimizations:
    > they're evil evil evil. An incorrect program can be as fast as you want
    > since it doesn't need to do anything, but generally that's not what you
    > ultimately want. So, think first correctness, not micro-optimization.
    >


    I only used memcpy in the example text to illustrate what the 3rd part
    database is doing.

    So given that I am stuck with this 3rd party database system, which
    does do binary copying as it was originally designed using C as
    opposed to C++ and probably still is using C, can I assume that a
    class without any virtual functions will be safe in this instance or
    should I change my code to use something like a unsigned char array to
    store the values of foo in?

    BTW, the binary copy is performed on bar not foo.

    > --
    > A: Because it messes up the order in which people normally read text.
    > Q: Why is it such a bad thing?
    > A: Top-posting.
    > Q: What is the most annoying thing on usenet and in e-mail?
     
    Pep, Aug 17, 2007
    #3
  4. Pep wrote:
    > I'm getting weird results at the moment so thought I'd rebase my
    > knowledge of c++ storage with your help :)
    >
    > I have a class used as a type in a struct and the struct is handled by
    > a 3rd party binary writed for persistent storage. I am confused by the
    > results I am getting and am not sure how the 3rd party writer is
    > seeing the size of the stuct.
    >
    > class foo
    > // I have not included the methods for brevity
    > {
    > public:
    > unsigned short shortArray[4];
    > };


    It makes a difference what kind of "methods" this class has. If it
    doesn't have user-defined constructors, or virtual functions, it's
    most likely a POD class, which means it's safe to use 'memcpy' on it.

    > typedef struct
    > {
    > foo fooVar;
    > char charArray[8];
    > } bar;


    Tell us, why do you do the wicked typedef dance here? Why don't you
    simply write

    struct bar
    {
    foo fooVar;
    char charArray[8];
    };

    ?

    >
    > So if you do a sizeof(foo) you get back 8 as a result


    OK, so your 'short' is 2 bytes long, most likely.

    > and a
    > sizeof(bar) returns 16.


    It seems that the compiler adds no padding in the 'bar' objects.

    > However the class foo has methods as well.


    Again, depends on what methods those are.

    > Now
    > if I was to do any form of binary copy on bar such as using memcpy for
    > example using the sizeof(bar) as the length, will I definitely be
    > copying the complete data in bar or will the operation be thrown out
    > by things like internal members in foo created by the compiler, like
    > the vtbl in foo?


    If sizeof(foo) == sizeof(short[4]), there are no "internal members"
    with which you need to concern yourself.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 17, 2007
    #4
  5. Pep

    Pep Guest

    Victor Bazarov wrote:
    > Pep wrote:
    > > I'm getting weird results at the moment so thought I'd rebase my
    > > knowledge of c++ storage with your help :)
    > >
    > > I have a class used as a type in a struct and the struct is handled by
    > > a 3rd party binary writed for persistent storage. I am confused by the
    > > results I am getting and am not sure how the 3rd party writer is
    > > seeing the size of the stuct.
    > >
    > > class foo
    > > // I have not included the methods for brevity
    > > {
    > > public:
    > > unsigned short shortArray[4];
    > > };

    >
    > It makes a difference what kind of "methods" this class has. If it
    > doesn't have user-defined constructors, or virtual functions, it's
    > most likely a POD class, which means it's safe to use 'memcpy' on it.
    >
    > > typedef struct
    > > {
    > > foo fooVar;
    > > char charArray[8];
    > > } bar;

    >
    > Tell us, why do you do the wicked typedef dance here? Why don't you
    > simply write
    >
    > struct bar
    > {
    > foo fooVar;
    > char charArray[8];
    > };
    >
    > ?


    The original code which runs over 100's of 1,000's of lines was
    written by a non programmer! So that is the syntax he used and one
    that I have ashamedly got used to doing on this project :(

    He also did things like code a module for one entity of the business
    over around 125,000 lines of code then did a complete copy of the
    source files, just changing the names of the files and classes held in
    them to handle another entity which differs minimally in function.
    Makes a mockery of polymorphism, overloading and just about any other C
    ++ features you can name ROFL

    Still the original author made a couple of million bucks for his
    efforts so I guess it proves that clean code was not an issue to ones
    earnings in the dot com era.

    >
    > >
    > > So if you do a sizeof(foo) you get back 8 as a result

    >
    > OK, so your 'short' is 2 bytes long, most likely.
    >
    > > and a
    > > sizeof(bar) returns 16.

    >
    > It seems that the compiler adds no padding in the 'bar' objects.
    >
    > > However the class foo has methods as well.

    >
    > Again, depends on what methods those are.
    >
    > > Now
    > > if I was to do any form of binary copy on bar such as using memcpy for
    > > example using the sizeof(bar) as the length, will I definitely be
    > > copying the complete data in bar or will the operation be thrown out
    > > by things like internal members in foo created by the compiler, like
    > > the vtbl in foo?

    >
    > If sizeof(foo) == sizeof(short[4]), there are no "internal members"
    > with which you need to concern yourself.
    >


    Well the sizes I am getting back from foo and bar are the same using
    sizeof() but foo does have a couple of ctors and a couple of embedded
    classes, here's a bit more of the class to show the relevant parts

    class foo
    {
    public:
    class ZeroDivide : public std::exception
    {
    const char * what() const throw() ;
    };

    class Overflow : public std::exception
    {
    const char * what() const throw() ;
    };

    foo(unsigned long ls = 0, unsigned long ms = 0);

    foo(unsigned char c[8]);

    unsigned short shortArray[4];
    };

    The compiler I'm using is GNU g++ version 3.3.5

    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask
     
    Pep, Aug 17, 2007
    #5
  6. Pep wrote:
    > So if you do a sizeof(foo) you get back 8 as a result and a
    > sizeof(bar) returns 16. However the class foo has methods as well. Now
    > if I was to do any form of binary copy on bar such as using memcpy for
    > example using the sizeof(bar) as the length, will I definitely be
    > copying the complete data in bar or will the operation be thrown out
    > by things like internal members in foo created by the compiler, like
    > the vtbl in foo?


    How can foo have a virtual table when it has no virtual methods?
    If it had a virtual table you would see it in the size of foo:
    Instead of being 8 (ie. 4 2-byte shorts) it would probably be
    12 (or 16 if you are compiling in a 64-bit system). That's because
    a class with virtual methods has (in most compiler implementations)
    a pointer to the virtual table inside it.

    Even if it had virtual methods, it doesn't really matter. The pointer
    to the virtual table will be the same for all objects of the same type.
    Thus if you copy an object of type foo to an object of type foo, the
    virtual table pointer will be the same.

    Exactly what kind of incomplete data would you expect memcpy() to copy
    in this case?
    Of course you should take into account that memcpy() skips
    constructors, copy constructors and assignment operators. Assuming you
    don't have any of those, I suppose it doesn't matter.
     
    Juha Nieminen, Aug 17, 2007
    #6
  7. Pep

    Pep Guest

    Juha Nieminen wrote:
    > Pep wrote:
    > > So if you do a sizeof(foo) you get back 8 as a result and a
    > > sizeof(bar) returns 16. However the class foo has methods as well. Now
    > > if I was to do any form of binary copy on bar such as using memcpy for
    > > example using the sizeof(bar) as the length, will I definitely be
    > > copying the complete data in bar or will the operation be thrown out
    > > by things like internal members in foo created by the compiler, like
    > > the vtbl in foo?

    >
    > How can foo have a virtual table when it has no virtual methods?
    > If it had a virtual table you would see it in the size of foo:
    > Instead of being 8 (ie. 4 2-byte shorts) it would probably be
    > 12 (or 16 if you are compiling in a 64-bit system). That's because
    > a class with virtual methods has (in most compiler implementations)
    > a pointer to the virtual table inside it.
    >


    Yep, it was more a badly worded question as to "what should I look out
    for" to refresh my memory as usually I no longer have to worry about
    the sort of things any more.

    > Even if it had virtual methods, it doesn't really matter. The pointer
    > to the virtual table will be the same for all objects of the same type.
    > Thus if you copy an object of type foo to an object of type foo, the
    > virtual table pointer will be the same.
    >
    > Exactly what kind of incomplete data would you expect memcpy() to copy
    > in this case?
    > Of course you should take into account that memcpy() skips
    > constructors, copy constructors and assignment operators. Assuming you
    > don't have any of those, I suppose it doesn't matter.


    Yep, I don;t really know if they are using memcpy in the database code
    or not as they are very cagey when we talk to them about their
    product. All I do know is that they are definitely doing binary copy
    (of some form) on the data we send which they expect to be a struct
    type.

    So basically from what I can glean from everyones answers is that I
    can rely on the result of the sizeof() off the struct against my
    knowledge of the sizeof the sum of the scalars in the struct and the
    class. As long as those are the same then I should have no problems.

    Cheers.
     
    Pep, Aug 17, 2007
    #7
  8. Pep

    red floyd Guest

    On Aug 17, 8:33 am, Pep <> wrote:
    > Juha Nieminen wrote:
    > > Pep wrote:
    > > > So if you do a sizeof(foo) you get back 8 as a result and a
    > > > sizeof(bar) returns 16. However the class foo has methods as well. Now
    > > > if I was to do any form of binary copy on bar such as using memcpy for
    > > > example using the sizeof(bar) as the length, will I definitely be
    > > > copying the complete data in bar or will the operation be thrown out
    > > > by things like internal members in foo created by the compiler, like
    > > > the vtbl in foo?

    >
    > > How can foo have a virtual table when it has no virtual methods?
    > > If it had a virtual table you would see it in the size of foo:
    > > Instead of being 8 (ie. 4 2-byte shorts) it would probably be
    > > 12 (or 16 if you are compiling in a 64-bit system). That's because
    > > a class with virtual methods has (in most compiler implementations)
    > > a pointer to the virtual table inside it.

    >
    > Yep, it was more a badly worded question as to "what should I look out
    > for" to refresh my memory as usually I no longer have to worry about
    > the sort of things any more.
    >
    > > Even if it had virtual methods, it doesn't really matter. The pointer
    > > to the virtual table will be the same for all objects of the same type.
    > > Thus if you copy an object of type foo to an object of type foo, the
    > > virtual table pointer will be the same.

    >
    > > Exactly what kind of incomplete data would you expect memcpy() to copy
    > > in this case?
    > > Of course you should take into account that memcpy() skips
    > > constructors, copy constructors and assignment operators. Assuming you
    > > don't have any of those, I suppose it doesn't matter.

    >
    > Yep, I don;t really know if they are using memcpy in the database code
    > or not as they are very cagey when we talk to them about their
    > product. All I do know is that they are definitely doing binary copy
    > (of some form) on the data we send which they expect to be a struct
    > type.
    >


    In that case, your best bet may be to create a POD type that mirrors
    your class, copy into the POD, and forward to the database class for
    serialization.

    Alternatively, if you can rewrite some of your code....

    struct PODdata
    {
    // all the POD data to be serialized goes here
    };

    class Myclass : private PODdata // note private inheritance
    {
    // methods, constructors, etc....
    public:
    PODdata* as_PODdata() { return this; }
    };

    And pass the result of as_PODdata() to your serializer.
     
    red floyd, Aug 17, 2007
    #8

  9. >
    > So basically from what I can glean from everyones answers is that I
    > can rely on the result of the sizeof() off the struct against my
    > knowledge of the sizeof the sum of the scalars in the struct and the
    > class. As long as those are the same then I should have no problems.
    >
    > Cheers.


    size of the struct may be greater than the sum of the sizes of its
    members due to alignment issues unless your compiler align them at
    byte
    boundaries which it doesn't if you haven't specifically said so.
     
    hurcan solter, Aug 17, 2007
    #9
  10. * Juha Nieminen:
    >
    > Even if it had virtual methods, it doesn't really matter. The pointer
    > to the virtual table will be the same for all objects of the same type.
    > Thus if you copy an object of type foo to an object of type foo, the
    > virtual table pointer will be the same.


    The OP specified "persistent storage".

    The vtable pointers need not be the same in different processes.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Aug 17, 2007
    #10
  11. hurcan solter wrote:
    > size of the struct may be greater than the sum of the sizes of its
    > members due to alignment issues unless your compiler align them at
    > byte
    > boundaries which it doesn't if you haven't specifically said so.


    Note that one cannot assume that elements in structs/classes can be
    packed at byte boundaries in all architectures. There exist
    architectures (such as the Sun UltraSparc) where it's just not possible
    to store multiple-byte elements at anything else than at word bounaries
    (trying to access a multiple-byte element not at word boundary will
    cause a bus error interrupt).
     
    Juha Nieminen, Aug 18, 2007
    #11
  12. Pep

    JohnQ Guest

    "Juha Nieminen" <> wrote in message
    news:46c64e2e$0$3230$...
    > hurcan solter wrote:
    >> size of the struct may be greater than the sum of the sizes of its
    >> members due to alignment issues unless your compiler align them at
    >> byte
    >> boundaries which it doesn't if you haven't specifically said so.

    >
    > Note that one cannot assume that elements in structs/classes can be
    > packed at byte boundaries in all architectures.


    Which may not be a problem if the program runs on the platform without
    communicating to another platform: "fix it up" at he boundary to match up
    with the characteristics of the platform that was chosen to represent the
    protocol.

    John
     
    JohnQ, Aug 18, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Shuo Xiang

    Stack space, global space, heap space

    Shuo Xiang, Jul 9, 2003, in forum: C Programming
    Replies:
    10
    Views:
    2,980
    Bryan Bullard
    Jul 11, 2003
  2. Christian Seberino
    Replies:
    21
    Views:
    1,801
    Stephen Horne
    Oct 27, 2003
  3. Ian Bicking
    Replies:
    2
    Views:
    1,107
    Steve Lamb
    Oct 23, 2003
  4. Ian Bicking
    Replies:
    2
    Views:
    784
    Michael Hudson
    Oct 24, 2003
  5. googleboy
    Replies:
    4
    Views:
    1,046
Loading...

Share This Page