PrithviJC
PrithviJC

Reputation: 393

Objects of size 0

I understand that empty classes in C++ have a size of 1 byte. However, I noticed that sizeof() returns 0 for objects of this class(in g++):

    class Boom{
        int n[0];
    }

I can print a valid memory location for a Boom object:

    Boom b;
    cout<<&b;

Is this particular memory location occupied? If I allocate memory later in the program, is there a chance that this location will be used?

Upvotes: 5

Views: 907

Answers (5)

Sebastian Mach
Sebastian Mach

Reputation: 39089

Code not valid.

A size of 0 is invalid, both for classes and arrays. The C++ standard says:

Sizeof [expr.sizeof]

[...] The size of a most derived class shall be greater than zero [...]

and

Arrays [dcl.array]

In a declaration T D where D has the form

    D1 [ constant-expressionopt] attribute-specifier-seqopt

[...] If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero [...]


Why compiles? Compiler extension!

If you turn on -pedantic with g++, you will receive the following warning (or error with pedantic-errors):

ISO C++ forbids zero-size array ‘n’

so your program is basically not valid, but can be compiled by means of a compiler extension to the C++ standard (unless you turn this extension off).

Note: Even though your compiler can report 0 for the class, it won't do so for any instance (a.k.a. object) of that class:

#include <iostream>
class Boom {
    int n[0];
};
int main() {
    std::cout << sizeof(Boom) << '\n';   // prints 0
    std::cout << sizeof(Boom()) << '\n'; // prints 1
}

Having objects of size-0 would go simply too far off the standard.

Citation by Stroustroup:

Why is the size of an empty class not zero?

To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:

class Empty { };

  void f()
  {
      Empty a, b;
      if (&a == &b) cout << "impossible: report error to compiler supplier";
      Empty* p1 = new Empty;
      Empty* p2 = new Empty;
      if (p1 == p2) cout << "impossible: report error to compiler supplier";
  } 

There is an interesting rule that says that an empty base class need not be represented by a separate byte:

   struct X : Empty {
        int a;
        // ...
   };

   void f(X* p)
   {
       void* p1 = p;
       void* p2 = &p->a;
       if (p1 == p2) cout << "nice: good optimizer";
   }

This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".

Upvotes: 6

James Kanze
James Kanze

Reputation: 153909

This is a g++ extension; the C++ standard doesn't allow arrays of 0 elements. I think that this extension was originally designed to do what using an incomplete array type as the final element does in C99, but in C99, it's only legal if the struct contains more than one member. As for what happens if you declare an array of Boom, you'll have to ask g++. (C99 avoids this issue by requiring at least one other member.)

The only real use for this feature is for variable length dynmamically allocated objects, e.g.:

struct Array
{
    size_t size;
    int data[];
};

//  ...
Array* p = (Array*)malloc(sizeof(Array) + n * sizeof(int));
p->size = n;

(This uses the C standard syntax.)

In C++, we'd normally just use std::vector and be done with it.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254461

Arrays cannot have zero size. If your compiler allows you to declare one, then the language doesn't specify how it behaves.

In this case, with this compiler, it does indeed appear that this allows two objects to occupy the same location:

Boom b[2];
std::cout << &b[0] << ' ' << &b[1] << std::endl;

// Output: 0x7fffffb23fdc 0x7fffffb23fdc

But other compilers may behave differently, or simply reject the invalid declaration (as GCC does if you specify -pedantic -Werror).

Upvotes: 8

Vlad from Moscow
Vlad from Moscow

Reputation: 310970

In this definition

class Boom{
    int n[0];
}

there are two errors.:) 1. You forgot to place a semicolon after the closing brace. 2. The size of an array may not be set to zero.

And even empty classes have sizes that are not equal to zero. For example

struct A {};

std::cout << sizeof( A ) << std::endl;

will return a value that greater than 0.

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409176

When you print &b you print the address of where the variable b is stored. And yes, this location will be occupied, by that variable. Even if an object have zero size during compilation (remember that sizeof is a compile-time operator), a variable of that object must be addressable during run-time, and so take up space in memory.

Upvotes: 0

Related Questions