vtbl inheritance

S

Serve Laurijssen

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?
 
R

RaZiel

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?

The vtbl will remain untouched, but if you are in doubt you could easily
verify by using the debugger.

- RaZ
 
G

Goran

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.

I, too, think this should work.
How does MSVC(2005) handle the Vtbl when inheriting from a
class with a vtbl?

Don't know about 2005 specifically, but 98, 2003 and 2008 do this:

class WithoutVtbl
m1
m2
....
mx

class WithVtbl
vtbl
m1
m2
....
mx

class WithoutWithVtbl : public WithoutVtbl, public WithVtbl
WithoutVtbl::m1
....
WithVtbl::vtbl
WithVtbl::m1
....

That is, VC sticks classes together, one after the other, possibly
with padding, in "order of derivation". But you should not rely on
that nor program against it. And there's no need, either. C++ language
is +/- well prepared for these situations.

That said... What you actually seem to want is a POD (Header), then a
derived POD from it (UnitHeader), then your actual object, and you
want 0-initialization of PODs. If so, you might want to try this
(discalimer: compiled with head-compiler 0.0.1 and tested with head-
test-suite 0.0.1):

UnitHeader zeroFilled();

In CHeader, you might have

CHeader::CHeader()
{
static_cast<UnitHeader&>(*this) = UnitHeader();
}

That is, you might rely on default initialization, that is provided by
the compiler when you use Type(), to get your zero bytes.

Goran.
 
J

James Kanze

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.)
In VC++ the vtable pointer will be in the
RefCounted base sub-object so will not be affected by the memset.

Really? I would have expected that it be in front of the
UnitHeader element, with another vptr in the RefCounted
subclass. (The vptr for CHeader has to point to a different
vtable than that of RefCounted.)
 
J

James Kanze

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.
I, too, think this should work.

It's certainly not guaranteed.
Don't know about 2005 specifically, but 98, 2003 and 2008 do this:
class WithoutVtbl
m1
m2
...
mx
class WithVtbl
vtbl
m1
m2
...
mx
class WithoutWithVtbl : public WithoutVtbl, public WithVtbl
WithoutVtbl::m1
...
WithVtbl::vtbl
WithVtbl::m1
...

Where does it put the second vptr?

In fact, that's not what VC++ 2005 nor g++ do. Interestingly
enough, they both systematically place base classes without
virtual functions *after* those with, in order to be able to get
by with only one vptr. (This has a second effect as well: the
memset trick will never cause a problem if the class which is
doing it happens to be the last one in the order the compiler
lays them out.

[...]
That said... What you actually seem to want is a POD (Header), then a
derived POD from it (UnitHeader), then your actual object, and you
want 0-initialization of PODs. If so, you might want to try this
(discalimer: compiled with head-compiler 0.0.1 and tested with head-
test-suite 0.0.1):
UnitHeader zeroFilled();

In CHeader, you might have

CHeader::CHeader()
{
static_cast<UnitHeader&>(*this) = UnitHeader();
}

Just:
CHeader::CHeader()
: UnitHeader()
{
}
should do the trick.
 
P

Paul

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

I don't know; all I know is that it is safe to call memset on POD objects
assuming sizeof is returning something sensible (i.e. ignoring the empty
base class optimization).

Just for fun:

struct a
{
a() : m(0x0A) {}
virtual ~a() {}
char m;
};

struct b_empty
{
};

struct b_not_empty
{
char m;
};

template <bool DoIt>
void memset(void* dest, int value, std::size_t size)
{
memset(dest, value, size);
std::cout << "called memset\n";
}
template <>
void memset<false>(void*, int, std::size_t)
{
std::cout << "didn't call memset\n";
}

template <typename T>
struct c : a, T
{
void set()
{
struct empty_one : T {};
struct empty_two : T {};
struct empty : empty_one, empty_two {};
memset<sizeof(empty) != sizeof(T)>((T*)this, 0x42, sizeof(T));

All this does is call an function overloaded for the evaluation of
(sizeof(empty) != sizeof(T)). T in this case is either b_empty or
b_not_empty.
}
};


int main()
{
c<b_empty> o1;
o1.set();
c<b_not_empty> o2;
o2.set();
}

:)
What did this prove other than the function template specailization is
dependant on sizeof(template para) ?
 
P

Paul

Leigh Johnston said:
Leigh Johnston said:
On 31/01/2011 15:58, Pete Becker wrote:
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 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.


I don't know; all I know is that it is safe to call memset on POD
objects assuming sizeof is returning something sensible (i.e. ignoring
the empty base class optimization).

Just for fun:

struct a
{
a() : m(0x0A) {}
virtual ~a() {}
char m;
};

struct b_empty
{
};

struct b_not_empty
{
char m;
};

template <bool DoIt>
void memset(void* dest, int value, std::size_t size)
{
memset(dest, value, size);
std::cout << "called memset\n";
}
template <>
void memset<false>(void*, int, std::size_t)
{
std::cout << "didn't call memset\n";
}

template <typename T>
struct c : a, T
{
void set()
{
struct empty_one : T {};
struct empty_two : T {};
struct empty : empty_one, empty_two {};
memset<sizeof(empty) != sizeof(T)>((T*)this, 0x42, sizeof(T));

All this does is call an function overloaded for the evaluation of
(sizeof(empty) != sizeof(T)). T in this case is either b_empty or
b_not_empty.
}
};


int main()
{
c<b_empty> o1;
o1.set();
c<b_not_empty> o2;
o2.set();
}

:)
What did this prove other than the function template specailization is
dependant on sizeof(template para) ?

Until you apologize for your earlier trolling and obnoxious outbursts I
will continue to show little respect for any of your subsequent posts;
i.e. don't expect any answers to your questions.
Are you referring to the argument where you think a member function is a
member of a class and not a member of an object?
I wonder if you still actually think you are right about that. PMSL. Of
course you were wrong all the time so why should I be the one to apologise
for your wrongness?
 
B

Bo Persson

Leigh said:
How individual subobjects (the bases in this case) are laid out
relative to each other doesn't have any bearing on calling memset
on a particular subobject. The subobject in question is POD and
therefore does not contain a vtable pointer; memset is fine.

/Leigh

It does matter that the most derived object is non-POD. That means
that you cannot use memset on it, not even if you cast the
this-pointer to a different type.

And why would you, when the initializer list does the same thing?


Bo Persson
 
B

Bo Persson

Leigh said:
Can you please cite the part of the standard which says that a
subobject of a non-POD object cannot be POD?

A member subobject can be a POD, but that is not what we have here.

Where does it say that static_cast<POD&>(*this) is a POD, when *this
is not?



Bo Persson
 
P

Paul

Leigh Johnston said:
On 31/01/2011 20:52, Paavo Helde wrote:

A member subobject can be a POD, but that is not what we have here.

Where does it say that static_cast<POD&>(*this) is a POD, when *this
is not?

Right, the standard has carefully excluded base class subobject POD-s
from
memcpy guarantees. I wonder if this is only done so in order to be
able to
call empty structs PODs?


Are you being sarcastic? My antenna cannot tell today. :D If not
whereabouts in the standard is the exclusion?

Never mind I think I have found it:

3.9/2:

For any trivially copyable type T, if two pointers to T point to
distinct T objects obj1 and obj2, where
neither obj1 nor obj2 is a base-class subobject, if the underlying bytes
(1.7) making up obj1 are copied
into obj2,42 obj2 shall subsequently hold the same value as obj1. [
Example:
41) By using, for example, the library functions (17.6.1.2) std::memcpy
or std::memmove.
42) By using, for example, the library functions (17.6.1.2) std::memcpy
or std::memmove.
§ 3.9 72

c ISO/IEC N3225=10-0215
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p
contains
// the same value as the corresponding subobject in *t2p
—end example ]

I think I might owe James a second apology of the month.

Unfortunately I tend to mostly call on my own experience a lot of which is
Microsoft/VC++; so for example Microsoft's afx.h (part of MFC) has the
following beauty:

// zero fill everything after the vtbl pointer
#define AFX_ZERO_INIT_OBJECT(base_class) \
memset(((base_class*)this)+1, 0, sizeof(*this) - sizeof(class
base_class));

So Microsoft seem to have no problem with calling memset on parts of
non-PODs; this is obviously very poor even if it does work on VC++.

So yeah James you seem to be correct and I apologize.

/Leigh

You don't half talk some nonsense dude.
 
P

Paul

Leigh Johnston said:
Leigh Johnston said:
On 31/01/2011 21:18, Leigh Johnston wrote:
On 31/01/2011 21:11, Leigh Johnston wrote:
On 31/01/2011 20:52, Paavo Helde wrote:

A member subobject can be a POD, but that is not what we have here.

Where does it say that static_cast<POD&>(*this) is a POD, when *this
is not?

Right, the standard has carefully excluded base class subobject POD-s
from
memcpy guarantees. I wonder if this is only done so in order to be
able to
call empty structs PODs?


Are you being sarcastic? My antenna cannot tell today. :D If not
whereabouts in the standard is the exclusion?


Never mind I think I have found it:

3.9/2:

For any trivially copyable type T, if two pointers to T point to
distinct T objects obj1 and obj2, where
neither obj1 nor obj2 is a base-class subobject, if the underlying
bytes
(1.7) making up obj1 are copied
into obj2,42 obj2 shall subsequently hold the same value as obj1. [
Example:
41) By using, for example, the library functions (17.6.1.2) std::memcpy
or std::memmove.
42) By using, for example, the library functions (17.6.1.2) std::memcpy
or std::memmove.
§ 3.9 72

c ISO/IEC N3225=10-0215
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p
contains
// the same value as the corresponding subobject in *t2p
—end example ]

I think I might owe James a second apology of the month.


Unfortunately I tend to mostly call on my own experience a lot of
which is Microsoft/VC++; so for example Microsoft's afx.h (part of
MFC) has the following beauty:

// zero fill everything after the vtbl pointer
#define AFX_ZERO_INIT_OBJECT(base_class) \
memset(((base_class*)this)+1, 0, sizeof(*this) - sizeof(class
base_class));

So Microsoft seem to have no problem with calling memset on parts of
non-PODs; this is obviously very poor even if it does work on VC++.

So yeah James you seem to be correct and I apologize.

/Leigh

You don't half talk some nonsense dude.

You have already shown yourself to be *both* clueless and lacking in
humility as you refuse to apologize for your trolls and obnoxious
outbursts. I am able to admit when I am wrong and I was wrong in this
particular case as the standard does give special treatment to base class
subobjects versus other types of objects.
As I said you don't half talk some nonsense :)
 
P

Paul

Leigh Johnston said:
Well relying on knowledge of implementation specific behaviour when taking
part in discussions in forums such as this can be problematic. Must try
harder.
Yup you must.
As it happens I don't memset or memcpy any base class subobjects in my
code. :)
Glad to hear it.


Your still wrong about objects and member functions.
Pity you're too dense to understand that.

:)
 
J

James Kanze

On 2011-01-31 09:43:33 -0500, Leigh Johnston said:

[...]
Where can you find that in the standard? The definition of
sizeof (§5.3.3) says that "The result of applying sizeof to
a base class subobject is the size of the base class type."
I can find no words which guarantee that a base class subobject
actually occupies all of these bytes, and there is at least one
specific case (an empty base class) where this is not required.
struct S { };
struct T : S { int i; };
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.

But is this liberty really only restricted to empty base
classes. Given something like:

struct B { double d; char c; };
struct D : B { int i; };

and the alignment requirements double -> 8 and int ->4, could
an implementation lay it out with the offset of D::i at 12, even
though sizeof B is 16. This is what I would expect; that the
freedom given for empty base classes was general. And I can't
really find any text forbidding it.
 
J

James Kanze

[..]
In VC++ the vtable pointer will be in the
RefCounted base sub-object so will not be affected by the memset.
Really? I would have expected that it be in front of the
UnitHeader element, with another vptr in the RefCounted
subclass. (The vptr for CHeader has to point to a different
vtable than that of RefCounted.)
No, it doesn't as vtable is inherited only from one branch of the
multiple inheritance tree. VS2010 keeps the vtable pointer in the
RefCounted subobject and fills it in with CHeader virtual function
pointers (destructor only in this example).

So I see. But to do this, it rearranges the object, so that the
CHeader subobject has the same address as the most derived
object. Without this rearrangement (which is perfectly valid),
it would need a vptr for the CHeader, and another for the most
derived object, since code will access the vptr from the address
it has.
Even if the compiler decided to add another vtable pointer somewhere in
the object this would not affect memset of the UnitHeader POD object in
any way.

This is where I'm not sure. I don't think that a base object is
required to occupy sizeof(Base) bytes; it certainly isn't if the
base is empty, and in general, the wording of sizeof seems to
suggest that it might not be valid when used on base classes.
 
A

Alf P. Steinbach /Usenet

* James Kanze, on 01.02.2011 13:00:
Given something like:

struct B { double d; char c; };
struct D : B { int i; };

and the alignment requirements double -> 8 and int ->4, could
an implementation lay it out with the offset of D::i at 12, even
though sizeof B is 16.

No.

In essence (although I just skimmed previous discussion so may not have
registered all the salient points) Leigh is right.

Empty base class is another matter.

This is what I would expect; that the
freedom given for empty base classes was general. And I can't
really find any text forbidding it.

D oh = {1, 2, 3};
B& b = oh;

b = B(); // Should not affect D::i
assert( oh.i == 3 );

Taking the previous argumentation to the limit one could argue that a C++
compiler is not permitted to generate a simple memcpy for the B assignment, but
should inefficiently copy each member individually, each with just-so size.

Such an argument would then be an unintended proof in the tradition of
"reduction to the laughably absurd".


Cheers & hth.,

- Alf
 
P

Paul

Leigh Johnston said:
Given your past mutterings I doubt very much that you understand the
issues involved to be able to comment.


Again given your past mutterings I doubt very much that you understand the
issues involved to be able to comment.


You are the one who continues to show ignorance and "denseness". In C++
member functions are members of classes not objects; in C++ an object is
simply a region of storage (and possibly no storage at all for the type of
subobjects under discussion).
You don;'t have a clue whaT YOU'RE TALKING ABOUT. You've just been arguing
for 3 days about the construction of an object in memory and proven to be
wrong in the end.

How can you say a C++ memeber function is not part of an object and part of
a class? What a complete idiot to not even realise that an object is a
runtime entity while a class is a compile time entity. I'm not even going to
get into that argument again as I already proven you wrong with quotations
from Stroustrup. All you did was run from the argument with an outburst of
insults about trolling etc.
You are a dickhead a moron and a thick fooker so go blow your own trumpet
elsewhere.

:)
..
 
P

Paul

I admit my mistakes; you do not.


Rather than admitting to your mistake you resort to insults and trolling
and repeating your mistake.

I flick you off the table again with three simple words: INLINED MEMBER
FUNCTION.


Is there some special calling syntax for inlined functions that they do not
require an object? maybe I miss something but I don't see how these 3 words
support your argument.
 
P

Paul

Leigh Johnston said:
BTW you are trolling because you are deliberately introducing a straw man:
it was *I* who told *you* that classes only exist at compile time and
objects only exist at runtime; everything else follows from this C++
axiom.
Err no you didn't tell me when anything exists.
[cluelessness snip, insufficient respect to answer question]
Typical reaction of a loser.
Run baby run. you lose the argument but you can't admit you're wrong.
 
P

Paul

Leigh Johnston said:
You are either lying or having problems with your memory; one only has to
look back at my previous posts to see that I am telling the truth.
You speak total nonsense.
*You* are using a class as an argument against an object, this very fact
proves you are confused by runtime and precompile time.

I will argue no more about who said what first as obviously I am telling
you, and not vice versa. The very fact that you try to diverse from the real
argumement is further evidence that you are indeed very wrong.

[cluelessness snip, insufficient respect to answer question]

/Leigh
 
P

Paul

Leigh Johnston said:
ORLY?

On 3rd Jan I said:

"Of course I am correct. An object is an *instance* of a class; an
object is not a class. A class is a compile time artefact; an object is
a runtime artefact.

/Leigh" http://groups.google.com/group/comp.lang.c++/msg/1add28dbb917e1c4
You say this yet you argue that a member function does not belong to an
object because it belongs to a class. This just shows how stupid you are.
You do nothing but try to reduce the argument to newbie concepts.
 

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,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top