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

P

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 :)
 
A

Alf P. Steinbach

* 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.
 
P

Pep

Alf said:
* 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.
 
V

Victor Bazarov

Pep said:
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
 
P

Pep

Victor said:
Pep said:
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
 
J

Juha Nieminen

Pep said:
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.
 
P

Pep

Juha said:
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.
 
R

red floyd

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.



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.
 
H

hurcan solter

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.
 
A

Alf P. Steinbach

* 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.
 
J

Juha Nieminen

hurcan said:
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).
 
J

JohnQ

Juha Nieminen said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top