size of Empty Class

R

Reetesh Mukul

Hi,

Is the sizeof Empty Class is always defined to be 1 ? What does
standards says about it ?

With Regards,
Reetesh Mukul
 
A

Alf P. Steinbach

* Reetesh Mukul:
Is the sizeof Empty Class is always defined to be 1 ?
No.


What does standards says about it ?

It allows that size to be anything >0.

However, the sizeof(T) does not necessarily reflect the size used in memory in
the context of inheritance.

In that context the compiler is free to optimize away an empty base class
sub-object, called the Empty Base Class optimization.


Cheers & hth.,

- Alf
 
M

Marco Nef

What does standards says about it ?
It allows that size to be anything >0.

However, the sizeof(T) does not necessarily reflect the size used in
memory in the context of inheritance.

In that context the compiler is free to optimize away an empty base class
sub-object, called the Empty Base Class optimization.

I can reproduce that an empty class has 1 byte in VisualC++, what I'm quite
surprised about. But on the other hand Bjarne Stroustrup writes in his book
"The C++ programming language" that "the sizeof operator yields the size, in
bytes, of its operand". There is nothing like ">0". Where have you found
that information?

Marco
 
A

Alf P. Steinbach

* Marco Nef:
I can reproduce that an empty class has 1 byte in VisualC++, what I'm
quite surprised about. But on the other hand Bjarne Stroustrup writes in
his book "The C++ programming language" that "the sizeof operator yields
the size, in bytes, of its operand". There is nothing like ">0". Where
have you found that information?

The C++ standard, on sizeof.


Cheers & hth.,

- Alf
 
M

Marco Nef

The C++ standard, on sizeof.

But where in the standard? 5.3.3 does not say that.

By the way: Where can I actually download the versions of the standard other
than the current draft?

- Marco
 
R

Reetesh Mukul

* Marco Nef:



The C++ standard, on sizeof.

Cheers & hth.,

- Alf

namespace nirved{
struct void_{};
template<typename T = void_> struct ordinal;
template<> struct ordinal<void_>
{
typedef void_ previous_type;
};
template<> struct ordinal<ordinal<void_> >
: private ordinal<void_>
{
typedef ordinal<void_> previous_type;
previous_type x;
void_ x;
};

template<> struct ordinal<ordinal<ordinal<void_> > >
: private ordinal<ordinal<void_> >
{
typedef ordinal<ordinal<void_> > previous_type;
previous_type x;
void_ x;
};

template<typename T> struct ordinal//:
public T
{
typedef T previous_type;
previous_type x;
void_ x;
};

}

int main()
{
typedef nirved::eek:rdinal<> zero;
typedef nirved::eek:rdinal<zero> one;
typedef nirved::eek:rdinal<one> two;
typedef nirved::eek:rdinal<two> three;
typedef nirved::eek:rdinal<three> four;
typedef nirved::eek:rdinal<four> five;
std::cout << sizeof(five);
return 0;
}

Thus sizeof(five)==5 has undefined result ?

With Regards,
Reetesh Mukul
 
A

Alf P. Steinbach

* Marco Nef:
But where in the standard? 5.3.3 does not say that.

§5.3.3/2 "The size of a most derived class shall be greater than zero"

By the way: Where can I actually download the versions of the standard
other than the current draft?

Best place would be ANSI, they're one order of magnitude cheaper than ISO.

You can also download the previous Committee Draft 1 (CD1) for free from various
places, probably still including Bjarne Stroustrup's pages. It's pretty much
identical to the C++98 standard. However, Technical Corrigendum (TC1) in 2003,
known as C++03, fixed a large number of errors and added "value initialization".

Of old some people used to recommend instead just bying Schildt's annotated C++
standard book, where each second page quoted the standard and each other second
page contained Schildt's commentary. Much cheaper than buying the standard from
ISO. The joke was that the lower price reflected the value of the comments.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Reetesh Mukul:
int main()
{
typedef nirved::eek:rdinal<> zero;
typedef nirved::eek:rdinal<zero> one;
typedef nirved::eek:rdinal<one> two;
typedef nirved::eek:rdinal<two> three;
typedef nirved::eek:rdinal<three> four;
typedef nirved::eek:rdinal<four> five;
std::cout << sizeof(five);
return 0;
}

Thus sizeof(five)==5 has undefined result ?

No.


Cheers & hth.,

- Alf
 
M

Marco Nef

§5.3.3/2 "The size of a most derived class shall be greater than zero"

Thank you, I found it. The reason must be arrays... I don't like this
paragraph, but it is standard.

- Marco
 
J

James Kanze

Thank you, I found it. The reason must be arrays... I don't
like this paragraph, but it is standard.

The reason is identity, in general. If objects could have 0
size, you could end up with two different objects at the same
address.
 
K

Kai-Uwe Bux

Reetesh said:
If sizeof({}) is >0 then why should sizeof(5)==5 will be true always ?

This seems like a case of miscommunication. You first asked:

Thus sizeof(five)==5 has undefined result ?

The answer is "no". Note that "undefined" has a technical meaning in the C++
standard. And the expression "sizeof(five)==5" does not involve undefined
behavior.

_Now_, you wonder:

If sizeof({}) is >0 then why should sizeof(5)==5 will be true always ?

This is a totally different question. Although sizeof(five)==5 is not
undefined, it is by no means guaranteed to be true.


Best

Kai-Uwe Bux
 
P

Pascal J. Bourguignon

James Kanze said:
The reason is identity, in general. If objects could have 0
size, you could end up with two different objects at the same
address.

void* p=malloc(0);
void* q=malloc(0);
assert((p!=NULL) and (q!=NULL) and (p!=q));

If C can do it with malloc, why C++ couldn't do it with classes and new?

That said, perhaps malloc(0) does allocate 1 byte behind the scene
(at least, it will allocate the overhead), and it may be simplier for
C++ implementations to have sizeof(Empty)==1; but conceptually we
don't need it, and implementation needs shouldn't transpire at the
user's level...

------------------------------------------------------------------------
#include <ciso646>
#include <iostream>
#include <cassert>

void c(){
void* p=malloc(0);
void* q=malloc(0);
assert((p!=NULL) and (q!=NULL) and (p!=q));
}

class Empty{};
class SubEmpty:public Empty{};

void cpp(){
Empty* p=new Empty();
SubEmpty* q=new SubEmpty();
std::cout<<"sizeof(*p)="<<sizeof(*p)<<std::endl;
std::cout<<"sizeof(*q)="<<sizeof(*q)<<std::endl;
assert((p!=NULL) and (q!=NULL) and (p!=q));
}

int main(){
c();
cpp();
return(0);
}
/*
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Fri Mar 13 15:21:01

SRC="/tmp/m.c++" ; EXE="m" ; g++ -g3 -ggdb3 -o ${EXE} ${SRC} && ./${EXE} && echo status = $?
sizeof(*p)=1
sizeof(*q)=1
status = 0

Compilation finished at Fri Mar 13 15:21:02
*/
 
R

Reetesh Mukul

This seems like a case of miscommunication. You first asked:

 Thus sizeof(five)==5 has undefined result ?

The answer is "no". Note that "undefined" has a technical meaning in the C++
standard. And the expression "sizeof(five)==5" does not involve undefined
behavior.

_Now_, you wonder:

  If sizeof({}) is >0 then why should sizeof(5)==5 will be true always ?

This is a totally different question. Although sizeof(five)==5 is not
undefined, it is by no means guaranteed to be true.

Best

Kai-Uwe Bux

Yes, I did mistake. I should have rather written unspecified behavior.
 
D

Default User

Pascal said:
void* p=malloc(0);
void* q=malloc(0);
assert((p!=NULL) and (q!=NULL) and (p!=q));

If C can do it with malloc, why C++ couldn't do it with classes and
new?

This is explicitly covered in C. From standard (recent draft):

7.20.3 Memory management functions
1 The order and contiguity of storage allocated by successive calls to
the calloc, malloc, and realloc functions is unspecified. The pointer
returned if the allocation succeeds is suitably aligned so that it may
be assigned to a pointer to any type of object and then used to access
such an object or an array of such objects in the space allocated
(until the space is explicitly deallocated). The lifetime of an
allocated object extends from the allocation until the deallocation.
Each such allocation shall yield a pointer to an object disjoint from
any other object. The pointer returned points to the start (lowest byte
address) of the allocated space. If the space cannot be allocated, a
null pointer is returned. If the size of the space requested is zero,
the behavior is implementationdefined: either a null pointer is
returned, or the behavior is as if the size were some nonzero value,
except that the returned pointer shall not be used to access an object.


So, a call to malloc(0) might return a null pointer, or it might not,
depending on your implementation. The behavior you see is one possible
result. When it does return a non-null pointer, you can't dereference
it, but it must be unique. You don't really have objects at those
pointers you got. The only thing you can do is compare the pointers or
pass them to realloc() or free().


Empty structs are illegal in C, so this concern doesn't come up in that
language at all. You don't have the same thing going on.



Brian
 
J

James Kanze

Would they be "different" objects at that point? I'm thinking
of EBO.

Most of the time there should be no problem, since identity is
really only relevant between objects of the same type. There
are some restrictions with regards to EBO, but there is a sense
in which I think it breaks the basic object model:

class B {} ;

class C : public B { B myB ; } ;

If the base object B of a class C and the member myB can have
the same address, I would consider it a defect in the language.
(I remember that this issue was discussed when EBO was
introduced, but I forget how it was handled.) More generally,
there's a real sense in which EBO is broken anyway---try
memcpy'ing the base, for example.

The real question is: do these violations of the principle have
any effects in real programs. I'd certainly never use anything
involving memcpy or its likes on a base class (even without
EBO). And I can't off hand think of a case where I've seen a
class with a base class and the first member of the same type.
Practically, most of the "empty" base classes I've seen are of
the std::iterator sort---any real base class (i.e. in the OO
sense, where you'd expect an object) would have at least a vptr.
So on the hold, the rules seem a good compromise, even if they
are theoretically broken.
 
J

James Kanze

void* p=malloc(0);
void* q=malloc(0);
assert((p!=NULL) and (q!=NULL) and (p!=q));
If C can do it with malloc, why C++ couldn't do it with
classes and new?

I'm not sure what you mean by "do it". There's no problem with
the above in C++ either. And it has nothing to do with sizeof.
 
D

Default User

James said:
I'm not sure what you mean by "do it". There's no problem with
the above in C++ either. And it has nothing to do with sizeof.

I think the "it" referred to his running a test will malloc and getting
two non-equal pointers. That's not even guaranteed to do that on every
implementation (although it must be defined). In C it's a non-starter,
as there are no empty structs. You can't have sizeof (sometype) result
in 0, so his test is pointless.

As I mentioned elsewhere, the C standard explicitly covers the case of
passing 0 to malloc(). However, even when unique pointers are returned,
you can't access objects at those locations. I don't know if you could
even say that there are objects at those locations.




Brian
 

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

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top