Sam Hobbs

I expected the offset of member m_RecordSize to be zero for both classBase and classDerived in the following but instead m_RecordSize is at offset 4 within classDerived. Is this due to the vtable in classDerived

For what it is worth, the reason this is important is because I have many more classes derived from classDerived that I am writing to disk so I need to ensure I understand the format of the data in memory. Everything else is working; packing is not a problem and such.

Code Snippet

class classBase {

public:

classBase() : m_RecordType(Function_Unknown), m_RecordSize(0),

m_ReturnCode(0), m_Time(0) {};

size_t m_RecordSize;

unsigned _int64 m_Time;

DWORD m_ReturnCode;

enum enumRecordType {

Function_Unknown,

Function_Begin,

Function_End,

Function_Message,

} m_RecordType;

};

class classDerived : public classBase {

public:

classDerived();

virtual ~classDerived() {};

LPVOID m_p;

static const size_t InternalDataSize;

};

class classLogger {

public:

void Put(const classDerived *);

};

void classLogger::Put(const classDerived *pd) {

// &pd->m_RecordSize is 4 bytes greater than pd

};



Re: Visual C++ Language Member offsets in derived classes

einaros

Sam Hobbs wrote:

I expected the offset of member m_RecordSize to be zero for both classBase and classDerived in the following but instead m_RecordSize is at offset 4 within classDerived. Is this due to the vtable in classDerived

Yes, the first four bytes would be the virtual table pointer.






Re: Visual C++ Language Member offsets in derived classes

Ramkrishna Pawar

IMO apart from the vptr being the first 4 bytes, you can't be sure of other member's position, it's compiler dependant.




Re: Visual C++ Language Member offsets in derived classes

einaros

Yep. Using some (configurable) serialization library would be a better solution. People are usually pretty set in their ways when it comes to that, though, so I suppose it's best experienced or dealt with on ones own.




Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

einaros wrote:
Yes, the first four bytes would be the virtual table pointer.

I would consider that to be an answer except the other replies indicate there is more that I need to know about other than packing and the vtable. I would expect the language to be clear enough to not require the additional software you suggest in your subsequent reply.





Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

Ramkrishna Pawar wrote:
IMO apart from the vptr being the first 4 bytes, you can't be sure of other member's position, it's compiler dependant.

I am quite nearly positive that a major purpose of structures originally were for storage to/from external media. Yes, I understand that the position is not guaranteed but we are talking about VC. So as far as VC is concerned, is there anything other than packing and the vtable that affects position All other compilers other than VC are irrelevant for this.





Re: Visual C++ Language Member offsets in derived classes

Sdi

Don't ever rely on in-memory representation matching persistent-storage representation; you simply can't control all the variables. Like Einar said, teach the classes to serialize themselves.



Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

Sdi wrote:
Don't ever rely on in-memory representation matching persistent-storage representation; you simply can't control all the variables. Like Einar said, teach the classes to serialize themselves.
If you can specify what else is included by "control all the variables" then that would really help; otherwise this comment is worthless. You say there are variables, but if you can't be specific about any of them then I will assume there are no other variables.

I know that you and Einar are ususlly accurate and very helpful, but my understanding on this subject varies considerably. My question is asking for specifics, not unsubstantiated opinions. If anyone can specify any variable other than the two I am aware of then I will have reason to be skeptical of my understanding.





Re: Visual C++ Language Member offsets in derived classes

Brian Kramer

The layout of a class is implementation dependent. In the absense of packing, the compiler usually (but is not required to) lay out the members in the order defined, with padding to maintain expected alignments of its members as well as keep the overall structure aligned. So some of the variables are: packing, alignment, and treatment of virtual functions, but there can be others. I think the other people in this thread are trying to say: "don't try to deduce this logic completely, becuase you're not supposed to."





Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

Brian Kramer wrote:

The layout of a class is implementation dependent.

How Except for the two already mentioned, what is another variable

Brian Kramer wrote:

In the absense of packing, the compiler usually (but is not required to) lay out the members in the order defined, with padding to maintain expected alignments of its members as well as keep the overall structure aligned.

I will try to find the relevant standard, but I will be surprised if the standard does not require that the compiler "lay out the members in the order defined".

Brian Kramer wrote:

So some of the variables are: packing, alignment, and treatment of virtual functions, but there can be others.

Packing and alignment are the same thing. Packing is the technique for acheiving alignment. So what is another variable If you know, then say so, otherwise you are guessing.

Brian Kramer wrote:

I think the other people in this thread are trying to say: "don't try to deduce this logic completely, becuase you're not supposed to."

My understanding is that structures were originally designed to allow storage to/from external media.




Re: Visual C++ Language Member offsets in derived classes

Brian Kramer

I don't know all the variables, nor would I really want to, because memory layout of C++ classes should not be assumed. This is common knowledge.

The compiler is not required to lay out the members in the order defined. That said, a compiler will usually abide by earlier behavior for binary compatibility (but it does still get broken from time to time). But if you compare, say, GCC and VC++, you will see that fields get laid out differently. In fact I recall Einer helping someone out on this issue in this forum once.

Packing and alignment are not the same thing; packing usually refers to placing fields at sub-word-size e.g. 32-b bits placement to save space. Alignment involves padding out fields so that they are a multiple of a word size, which costs extra space.

C/C++ structures are not designed for binary serialization--C++ programmers must manually serialize as been said in this thread before.





Re: Visual C++ Language Member offsets in derived classes

einaros

The standard quotes:

Two POD-struct (clause 9) types are layout-compatible if they have the same number of nonstatic data

members, and corresponding nonstatic data members (in order) have layout-compatible types (3.9).

And to be clear on the lingo:

A POD-struct is an aggregate class that has no non-static data members of type non-POD-struct,

non-POD-union (or array of such types) or reference, and has no user-defined copy assignment operator

and no user-defined destructor.

So as far as compatibility guarantees goes: you'll have none with your current tree. That's not to say that they won't be compatible, but you can't assume that neither the standard nor compiler expects you to want or need compatibility. That inherently means that layout *can* change, order *can* change, and for all you know pieces of data may be optimized away. Neither of these are very likely to happen, but that's the bottom line. What you do know is that the layout won't change once you've compiled your application, so doing the appropriate manual structural verification should be more than enough for you application to keep running as it should.






Re: Visual C++ Language Member offsets in derived classes

Sdi

I will try to find the relevant standard, but I will be surprised if the standard does not require that the compiler "lay out the members in the order defined".
Prepare to be surprised. Here's what the N2135 draft paper says; I don't have a copy of the 14882 language spec, but I expect that it's similar:

"Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1)."





Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

Brian Kramer wrote:

I don't know all the variables, nor would I really want to, because memory layout of C++ classes should not be assumed.

Yet you cannot provide clear evidence of what you say.

Brian Kramer wrote:

This is common knowledge.

I don't think so.

Brian Kramer wrote:

The compiler is not required to lay out the members in the order defined.

See the quote of the standard. It says that for members of the same access, the layout must be in an ascending sequence.

Brian Kramer wrote:

Packing and alignment are not the same thing; packing usually refers to placing fields at sub-word-size e.g. 32-b bits placement to save space. Alignment involves padding out fields so that they are a multiple of a word size, which costs extra space.

Yes, I was getting packing and padding confused. The standard however does not define nor uses the term memory "word", correct The standard only specifies bytes. I think the standard also prohibits packing, as in using portions of bytes. So I don't understand how packing has any relevance.





Re: Visual C++ Language Member offsets in derived classes

Sam Hobbs

einaros wrote:
That inherently means that layout *can* change, order *can* change, and for all you know pieces of data may be optimized away.

Actually the standard is saying that if the requirements for layout-compatibility are satisfied, I am guaranteed compatibility. Order can't change unless I change it.

einaros wrote:
What you do know is that the layout won't change once you've compiled your application, so doing the appropriate manual structural verification should be more than enough for you application to keep running as it should.

The standard does not limit compatibility to single instances of compiled code.