Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Empty objects as members

29 views
Skip to first unread message

Juha Nieminen

unread,
Nov 1, 2010, 1:57:29 PM11/1/10
to
I have got the impression from somewhere that if you have an empty
class (in other words one without any member variables) and you use
it as a member variable of another class, this empty object will take
at least one byte of space. In other words, the compiler is *not* allowed
to optimize it to taking no space at all. (The only situation where the
compiler is allowed to optimize it is inheritance, this being the so-called
"empty base class optimization".)

However, this is only an impression I got. I would like a confirmation
from the C++ standard. Could someone kindly refer me to the proper
section?

Victor Bazarov

unread,
Nov 1, 2010, 2:28:23 PM11/1/10
to

I think you are asking about 1.8 The C++ Object model, paragraphs 4 and
5 that describe what "the most derived object" is and that its size is
non-zero and that it occupies one or more bytes of storage.

V
--
I do not respond to top-posted replies, please don't ask

Balog Pal

unread,
Nov 1, 2010, 2:35:58 PM11/1/10
to
"Juha Nieminen"

1.8p5

Unless it is a bitfield (9.6), a most derived object shall have a nonzero
size and shall occupy one or more bytes of storage. Base class subobjects
may have zero size. An object of POD4) type (3.9) shall occupy contiguous
bytes of storage.

Larry Evans

unread,
Nov 1, 2010, 3:50:20 PM11/1/10
to
On 11/01/10 13:35, Balog Pal wrote:
[snip]

> 1.8p5
>
> Unless it is a bitfield (9.6), a most derived object shall have a
> nonzero size and shall occupy one or more bytes of storage. Base class
> subobjects may have zero size. An object of POD4) type (3.9) shall
> occupy contiguous bytes of storage.
>

Balog,

Would you happen to know the rationale for the different sizes used
for a base object and most derived object? It seems it would save
some space; do, why not save the space?

TIA.

-Larry

Victor Bazarov

unread,
Nov 1, 2010, 4:03:22 PM11/1/10
to

What would save the space? Making different members of some class have
the same address? Base class subobject is allowed to be of zero size
because in some cases its address can coincide with the address of the
derived object without introducing any ambiguities. Two base classes
[of the same derived class] cannot have the same address. Two members
of the same class cannot have the same address. Please elaborate on
your "space saving" idea.

Marcel Müller

unread,
Nov 1, 2010, 4:24:36 PM11/1/10
to
Victor Bazarov wrote:
> What would save the space? Making different members of some class have
> the same address? Base class subobject is allowed to be of zero size
> because in some cases its address can coincide with the address of the
> derived object without introducing any ambiguities.

I see, and I know of this restriction, of course.

But why must a pointer to a non polymorphic object be unique? They do
not support dynamic casts anyway. And why does this not apply to one
base class?


Marcel

Victor Bazarov

unread,
Nov 1, 2010, 4:34:12 PM11/1/10
to

I probably don't understand the question, but why would polimorphic-ness
matter?... Data members in the same object and elements of the same
array wouldn't be distinguishable if pointers weren't unique.

Howard Hinnant

unread,
Nov 1, 2010, 4:40:35 PM11/1/10
to
Saving space for empty data members has long been an optimization that
some people thought was worth fighting for. Every implementation of
every std::container I'm currently aware of optimizes away the space
for an empty allocator (for example).

The first I ever read about a general solution for this problem is
here:

http://www.cantrip.org/emptyopt.html

Next came boost::compressed_pair:

http://www.boost.org/doc/libs/1_44_0/libs/utility/compressed_pair.htm

And lately implementors have started giving the C++0x std::tuple this
optimization. All of the implementations are refinements of Nathan's
1997 paper; using derivation to achieve the optimization.

-Howard

Marc

unread,
Nov 1, 2010, 5:14:47 PM11/1/10
to
Victor Bazarov wrote:

> What would save the space? Making different members of some class have
> the same address? Base class subobject is allowed to be of zero size
> because in some cases its address can coincide with the address of the
> derived object without introducing any ambiguities. Two base classes
> [of the same derived class] cannot have the same address.

Are you sure about this last one? g++ seems to do the empty base class
optimization even if there are many such empty base classes.

Marcel Müller

unread,
Nov 1, 2010, 6:07:25 PM11/1/10
to
Victor Bazarov wrote:
>> But why must a pointer to a non polymorphic object be unique? They do
>> not support dynamic casts anyway. And why does this not apply to one
>> base class?
>
> I probably don't understand the question, but why would polimorphic-ness
> matter?...

Classes with at least one virtual function are guaranteed to support
RTTI. For this to work the relation between objects and pointers must be
bijective.

Data members in the same object and elements of the same
> array wouldn't be distinguishable if pointers weren't unique.

In my opinion there is no need to have unique pointer for zero length
objects, since non polymorphic objects always must have a static type,
known at compile time.

Most probably I missed something, but I don't know what.


Marcel

Larry Evans

unread,
Nov 1, 2010, 7:29:38 PM11/1/10
to
On 11/01/10 15:03, Victor Bazarov wrote:
> On 11/1/2010 3:50 PM, Larry Evans wrote:
>> On 11/01/10 13:35, Balog Pal wrote:
>> [snip]
>>> 1.8p5
>>>
>>> Unless it is a bitfield (9.6), a most derived object shall have a
>>> nonzero size and shall occupy one or more bytes of storage. Base class
>>> subobjects may have zero size. An object of POD4) type (3.9) shall
>>> occupy contiguous bytes of storage.
>>>
>>
>> Balog,
>>
>> Would you happen to know the rationale for the different sizes used
>> for a base object and most derived object? It seems it would save
>> some space; do, why not save the space?
>
> What would save the space? Making different members of some class have
> the same address?

Yes.

> Base class subobject is allowed to be of zero size
> because in some cases its address can coincide with the address of the
> derived object without introducing any ambiguities. Two base classes
> [of the same derived class] cannot have the same address. Two members
> of the same class cannot have the same address.

Why?

> Please elaborate on
> your "space saving" idea.

I suppose there's something dangerous about two members of the same
class having the same address, but I don't know what that danger is.

I've read:

http://www.cantrip.org/emptyopt.html

which says:

If you were keeping track of separate objects by their addresses, f.b
and f.a[0] would appear to be the same object. The Standard committee
chose to finesse these issues by forbidding zero-sized addressable
objects.

However, if a program has no need to keep track of separate objects by
their addresses, then what would be the harm of having two members with
the same address?

The real reason I'm interested is because:


https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/pack/container_all_of_aligned.hpp

can have something like 0 sized objects but they're really just
offsets into a buffer. The offset's are cast to the actual type
(properly aligned) and I'm worried that doing that is dangerous
for empty class objects somehow and I'd like to know what that
danger is before it "bites me" ;(

>
> V

Thanks for any enlightenment you could provide, Victor.

-Larry

PS, to illustrate, the attachment, when run, produces output:

sizeof(empty_class<0>)=1
sizeof(index_inherit<0,empties_inherit>)=1
sizeof(empties_inherit)=1
sizeof(empties_tree_inherit)=2
sizeof(empties_member)=2
sizeof(empties_all_of)=1
sizeof(empties_tree_all_of)=1
sizeof(empties_variant)=8
sizeof(empties_one_of)=1
sizeof(enum_base<index0>::type)=1
p0=0x7fff0fa29def
p1=0x7fff0fa29def
*p0=empty_class<0>const&
*p1=empty_class<1>const&
r0=empty_class<0>const&
r1=empty_class<1>const&
&ea_v=0x7fff0fa29dee
&r0=0x7fff0fa29dee
&r1=0x7fff0fa29dee
r1.get()=1

which illustrates that empty members occupy 1 byte
(the empties_member struct sizeof=2), but empties_inherit
does use EBO resulting in sizeof=1.

The empties_all_of sizeof=1 despite being similar
to empties_member.

However, is there some downside to empties_all_of?

empty_base.cpp

Victor Bazarov

unread,
Nov 2, 2010, 10:14:40 AM11/2/10
to

Most probably *I* didn't give it enough thought. What you're saying, I
think, is that if an object doesn't have a state and is not polymorphic
(IOW, doesn't have member data that can have [different] values or can
have a different dynamic type), there is no need to allocate storage for
it, right? To extend this reasoning, the member functions for such a
class don't have to have a unique 'this' pointer, since there is no
*need* to distinguish between objects (they are all the same), yes? The
objects of that type don't have identity, but the question to answer is,
"why would then need it?" The compiler then can optimize and reuse some
pointer for all 'this' pointers when calling their member functions,
yes? Now, imagine that the identity is not stored (state) but implied
in the behavior, like

int NoIdentityClass::foo(NoIdentityClass const& other) const
{
if (this == &other)
return 0;
else
return 42;
}

how would the compiler know not to optimize? I am not sure what the use
of such algorithm would be (so it could be just theoretical), but it's
quite real. I can write a program to have a limited number of some
stateless objects that would require to be unique, so I would need to
disallow the compiler to optimize the size to 0 for *that* particular
class. I am guessing that requiring the compiler to always allocate at
least one byte for those is both *inexpensive* and solves the identity
problem.

Anyway, interesting. Thanks for making me think about it.

Victor Bazarov

unread,
Nov 2, 2010, 10:32:58 AM11/2/10
to

My understanding is that the object is allowed to have behavior based on
the information provided to it by the system during run-time. For instance,

struct Hand {
void tap_fingers() const;
};

struct Man {
Hand left_hand, right_hand;
void tap_fingers(Hand* which_hand) {
if (which_hand == &right_hand) // do only if my right hand
which_hand->tap_fingers();
}
};

Imagine that in some environment where the size of 'Hand' is 0 and the
size of 'Man' is 0 as well (since it only has two objects of size 0, I
can give the man a command to tap some other Man's hand. That could
easily be against the model, so I would have to introduce some kind of
artificial discriminator to the Hand. Currently I don't need to.

>
> I've read:
>
> http://www.cantrip.org/emptyopt.html
>
> which says:
>
> If you were keeping track of separate objects by their addresses, f.b
> and f.a[0] would appear to be the same object. The Standard committee
> chose to finesse these issues by forbidding zero-sized addressable
> objects.
>
> However, if a program has no need to keep track of separate objects by
> their addresses, then what would be the harm of having two members with
> the same address?

Yes, if it doesn't, then... But how do you determine which class does
and which doesn't? It's quite difficult to deduce from the code, no? I
mean, for the compiler. So, it's easier to just always have 1 byte.

>
> The real reason I'm interested is because:
>
>
> https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/pack/container_all_of_aligned.hpp
>
> can have something like 0 sized objects but they're really just
> offsets into a buffer. The offset's are cast to the actual type
> (properly aligned) and I'm worried that doing that is dangerous
> for empty class objects somehow and I'd like to know what that
> danger is before it "bites me" ;(

Yeah, I don't know. I guess you can have an algorithm that doesn't care
about the addresses of individual objects in the current language
definition. Just have a class with all static members.

>
>>
>> V
>
> Thanks for any enlightenment you could provide, Victor.

I'm afraid I'm myself in the dark about it :-/

> -Larry

Larry Evans

unread,
Nov 2, 2010, 12:40:21 PM11/2/10
to
On 11/02/10 09:32, Victor Bazarov wrote:
> On 11/1/2010 7:29 PM, Larry Evans wrote:
[snip]

>>
>> I suppose there's something dangerous about two members of the same
>> class having the same address, but I don't know what that danger is.
>
> My understanding is that the object is allowed to have behavior based on
> the information provided to it by the system during run-time. For
> instance,
>
> struct Hand {
> void tap_fingers() const;
> };
>
> struct Man {
> Hand left_hand, right_hand;
> void tap_fingers(Hand* which_hand) {
> if (which_hand == &right_hand) // do only if my right hand
> which_hand->tap_fingers();
> }
> };
>
> Imagine that in some environment where the size of 'Hand' is 0 and the
> size of 'Man' is 0 as well (since it only has two objects of size 0, I
> can give the man a command to tap some other Man's hand. That could
> easily be against the model, so I would have to introduce some kind of
> artificial discriminator to the Hand. Currently I don't need to.

OK, in this special case; however, I was wondering if there's some
situation where two members having the same address would cause
undefined behaviour. In this cause, it just means you can't
discriminate between left_hand and right_hand based on address.

Of course if one had to discriminate on the basis of the address, one
could just add a dummy char to Hand to force it to occupy 1 byte.

>
>>
>> I've read:
>>
>> http://www.cantrip.org/emptyopt.html
>>
>> which says:
>>
>> If you were keeping track of separate objects by their addresses, f.b
>> and f.a[0] would appear to be the same object. The Standard committee
>> chose to finesse these issues by forbidding zero-sized addressable
>> objects.
>>
>> However, if a program has no need to keep track of separate objects by
>> their addresses, then what would be the harm of having two members with
>> the same address?
>
> Yes, if it doesn't, then... But how do you determine which class does
> and which doesn't? It's quite difficult to deduce from the code, no? I
> mean, for the compiler. So, it's easier to just always have 1 byte.
>
>>
>> The real reason I'm interested is because:
>>
>>
>> https://svn.boost.org/trac/boost/browser/sandbox/variadic_templates/boost/composite_storage/pack/container_all_of_aligned.hpp
>>
>>
>> can have something like 0 sized objects but they're really just
>> offsets into a buffer. The offset's are cast to the actual type
>> (properly aligned) and I'm worried that doing that is dangerous
>> for empty class objects somehow and I'd like to know what that
>> danger is before it "bites me" ;(
>
> Yeah, I don't know. I guess you can have an algorithm that doesn't care
> about the addresses of individual objects in the current language
> definition. Just have a class with all static members.
>

To be honest, originally, the container_all_of_aligned.hpp code
mentioned in my previous post couldn't have 0 sized members; however,
since boost spirit removes attributes with no data(Unused attributes):

http://www.boost.org/doc/libs/1_44_0/libs/spirit/doc/html/spirit
/karma/quick_reference/compound_attribute_rules.html

I thought it would be useful to allow 0 sized members in the
container_all_of_aligned. So far, I can see no disadvantage
except maybe the extra template metaprogramming; however, I
would think that spirit, in order to remove these Unused
attributes, would have to do some template metaprogramming also.
So, maybe there's no disadvantage w.r.t. Spirit. (BTW, I have hinted
at this to the Spirit deval ml).

>>
>>>
>>> V
>>
>> Thanks for any enlightenment you could provide, Victor.
>
> I'm afraid I'm myself in the dark about it :-/
>

OK, but thanks for considering the question.

-L

Bo Persson

unread,
Nov 2, 2010, 1:54:11 PM11/2/10
to

Many empty base classes of the same type?

Objects of different types can have the same address, like a class
object and its first member. Or a class object and its empty base
class.

But not several objects of the same type. Having the same address
would make them the same object!


Bo Persson


Bo Persson

unread,
Nov 2, 2010, 1:59:26 PM11/2/10
to
Victor Bazarov wrote:
> On 11/1/2010 7:29 PM, Larry Evans wrote:

>> However, if a program has no need to keep track of separate
>> objects by their addresses, then what would be the harm of having
>> two members with the same address?
>
> Yes, if it doesn't, then... But how do you determine which class
> does and which doesn't? It's quite difficult to deduce from the
> code,
> no? I mean, for the compiler. So, it's easier to just always have
> 1 byte.

But if you don't care about the identity of the member objects, why
would you have two members of that type in the first place?


Bo Persson


Bo Persson

unread,
Nov 2, 2010, 2:13:51 PM11/2/10
to

This was meant as a reply to Larry, not to Victor.


Bo Persson


Larry Evans

unread,
Nov 2, 2010, 6:02:33 PM11/2/10
to
On 11/02/10 13:13, Bo Persson wrote:
> Bo Persson wrote:
>> Victor Bazarov wrote:
>>> On 11/1/2010 7:29 PM, Larry Evans wrote:
>>
>>>> However, if a program has no need to keep track of separate
>>>> objects by their addresses, then what would be the harm of having
>>>> two members with the same address?
>>>
[snip]

>> But if you don't care about the identity of the member objects, why
>> would you have two members of that type in the first place?
>>
>>
>> Bo Persson
>
> This was meant as a reply to Larry, not to Victor.
[snip]

Good question! In my reply to Victor, I mentioned my motivation was
to emulate what Spirit did for spirit::unused. However, the
container_all_of_aligned, currently, instead of removing the unused
attribute(or actually, type, T, such that boost::is_empty<T>), simply
provides no space for it. Now, I could have removed it, like Spirit;
however, it just seemed simpler to just provide no space for it and
achieve the same space saving that Spirit gets. I could be wrong, but
it's worth a try ;)

James Kanze

unread,
Nov 3, 2010, 11:13:30 AM11/3/10
to

Exact. If the first member of the class has the same type as
a base, for example, the empty base class optimization doesn't
apply. (And g++ handles this correctly.)

--
James Kanze

Joshua Maurice

unread,
Nov 3, 2010, 5:35:48 PM11/3/10
to

I wondering if anyone can point to the parts of the (C++) standard
which require this. I'm recalling a conversation how this might have
been removed in a newer draft (or something), and I was wanting to
track this down.

jarppeeve

unread,
Aug 27, 2012, 7:33:41 PM8/27/12
to

Hi, I'm 15. I have 5" (i think you understand). Should i 'buy viagra'
(http://suqggm.buyonlineregular.com/?p=bwww.codingforum.org) - <a
href=http://myjayw.buyonlineregular.com/?p=awww.codingforum.org >buy
viagra</a> , 'The Website is Down - rhtjnv.buyonlineregular.com'
(http://rhtjnv.buyonlineregular.com/?p=swww.codingforum.org) buy viagra
to make it longer?


--
jarppeeve
------------------------------------------------------------------------
jarppeeve's Profile: http://forums.yourdomain.com.au/member.php?userid=811
View this thread: http://forums.yourdomain.com.au/showthread.php?t=609

0 new messages