On 2011-01-31 10:32:53 -0500, Leigh Johnston said:
On 31/01/2011 15:15, Pete Becker wrote:
On 2011-01-31 09:43:33 -0500, Leigh Johnston said:
On 31/01/2011 11:47, James Kanze wrote:
On Jan 30, 4:29 pm, Leigh Johnston<le...@i42.co.uk> wrote:
On 30/01/2011 16:14, Serve Laurijssen wrote:
Consider this code:
class RefCounted {
private: long m_nRefCount;
public: virtual ~RefCounted();
};
struct Header {
short us;
int i1;
int i2;
};
struct UnitHeader: public Header {
BYTE filler[sizeof(ULONG) - (sizeof(UnitHeader)& (sizeof(ULONG) -
1))];
};
class CHeader : public UnitHeader, public RefCounted {
};
RefCounted has a virtual destructor, UnitHeader and Header are POD
structs.
CHeader inherits from UnitHeader and RefCounted.
Now consider this:
void CHeader::MakeDummy() {
memset((UnitHeader*)this, 0, sizeof(UnitHeader));
}
The 'this' pointer in CHeader is casted to UnitHeader struct and
that
memory area set to zero.
But since the class inherits from a class with a virtual
destructor Im
not sure this works. How does MSVC(2005) handle the Vtbl when
inheriting
from a class with a vtbl?
That should work yes as you are calling memset on a POD base
sub-object
(of type UnitHeader).
I don't think it will fail in this particular case, because of
the data types involved and their respective alignment
requirements. But in general, the actual number of bytes
occupied by UnitHeader may be less than sizeof(UnitHeader) when
UnitHeader is a base class, so brutally writing
sizeof(UnitHeader) bytes is not a safe operation. (The "empty
base class optimization" is somewhat miss-named, because it
doesn't apply to only empty base classes.)
What is this nonsense? A base subobject is an object and in this case
the object is POD and it is fine to memset a POD object with
sizeof(POD object type) bytes.
struct S { };
struct T : S { int i; };
T t;
Clause 9 [classes]/3: "Complete objects and *member* subobjects of class
type shall have nonzero size" [emphasis added]. So sizeof(S) is required
to be at least 1. But when S is used as a base class of T the resulting
subobject is neither a complete object nor a member subobjct, so it is
not required to have nonzero size. That's the "empty base class
optimization". It allows objects of type T to occupy sizeof(int) bytes,
with the S subobject taking up no space. If the compiler does that,
calling memset((S*)&t, '\0', sizeof(S)) will write 1 byte into t, which
will overwrite one of the bytes of t's int member.
Fair enough but we are not dealing with empty base classes in this
case (James likes to troll with mostly irrelevant corner cases) and I
am assuming that it should always work when not dealing with empty
base classes (you wouldn't deliberately memset an empty base class
subobject). I only foresee a problem with a generic (template)
solution but you should be able to employ a trick to detect an empty
base class in this case.
Okay, so when you said "A base subobject is an object and in this case
the object is POD and it is fine to memset a POD object with sizeof(POD
object type) bytes" you meant "in this case the subobject's type is not
empty and the empty base class optimization does not apply".
I'm a bit concerned about "I am assuming that it should always work when
not dealing with empty base classes...". Assuming is dangerous. Can you
cite something in the language definition that requires memset to work
sensibly on base subobjects of non-zero size? In particular, note the
language about standard-layout classes in the C++0x working draft, which
clarifies some murky wording concerning PODs in C++03:
A standard-layout class is a class that:
...
either has no non-static data members in the most-derived class and
at most one base class with non-static data members, or has no base
classes with non-static data mebers, ...
...
[Note: standard-layout classes are useful for communicating with code
written in other
programming languages. ...]
The implication clearly being that assumptions about layout for
non-standard-layout classes are dangerous.
objects assuming sizeof is returning something sensible (i.e. ignoring