9

I've been reading about this stuff that size of an object should be at least 1 byte (C++: What is the size of an object of an empty class?) and what's wrong about having two empty objects the same address ? After all, we can have two pointers to the same object.

The googling tells me there is something about object identity fundemantal rule, but I can't find more detailed info about that.

So... $SUBJ.

Community
  • 1
  • 1
Andrew_Lvov
  • 4,621
  • 2
  • 25
  • 31

5 Answers5

7

Having two objects at the same address would mean that there would be no way to distinguish between these two objects when referencing them with pointers. For example, in the following code:

EmptyClass o1;
EmptyClass o2;

EmptyClass * po = &o;
po->foo();

Should the foo method be called on o1 or o2?

It could be argued that since these objects have no data and no virtual methods (otherwise they would have a non-zero size), it doesn't matter on which instance the method is invoked. However, this becomes more important when we want to test if two objects are equal (i.e. if they are the same):

template < typename T >
bool isSame( T const & t1, T const & t2 )
{
    return &t1 == &t2;
}

EmptyClass o1; // one object and...
EmptyClass o2; // ...a distinct object...

assert( ! isSame( o1, o2 ) ); // ...should not be one and same object!

For a more concrete example, let's assume that I want to associate some objects (I could say entities) with some values, let's say in an associative container:

Person you;
Person me;

// You and I are two different persons
// (unless I have some dissociative identity disorder!)
// Person is a class with entity semantics (there is only one 'me', I can't make
// a copy of myself like I would do with integers or strings)

std::map< Person *, std::string > personToName;

personToName[&you] = "Andrew_Lvov";
personToName[&me]  = "Luc Touraille";
// Oh, bother! The program confused us to be the same person, so now you and I
// have the same name!

So yes, it all boils down to object identity: if objects were allowed to be empty, they could be deprived of their identity, which is simply not allowed by the language (thankfully).

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
  • 1
    Yeah, that's a great explanation, thank you. One additional problem which actually arises: what if you have an array of empty objects. You can't select array member, since the array's size is 0. – Andrew_Lvov Feb 11 '11 at 16:38
  • @Andrew_Lvov: Well, I thought about adding that remark, but in fact I'm not sure this is an issue. Indeed, if I have the array `EmptyClass array[10]`, the code `array[3]` translates more or less to `*(array + 3 * sizeof( EmptyClass ))`; since `sizeof( EmptyClass ) == 0`, we end up accessing the object at the address `array`, which is indeed the fourth object of the array (as well as the first, second, third, etc.). – Luc Touraille Feb 11 '11 at 16:48
  • 1
    If two objects hold no state, they should be indistinguishable. Period. Alas, some time in the past the standard decided that objects should always be distinguishable and now we pay the price in places where we really would like to have 0-sized objects. – CygnusX1 Oct 22 '20 at 07:44
5

Every object must occupy distinct storage, otherwise you can't deallocate one object without deallocating others that share storage with it.

Suppose you have two distinct objects at one address:

Type* object1 = new Type(); //first object
Type* object2 = new Type(); //second object

and they happen to be at same addresses, then you

delete object1;

what will be deleted if they both have the same address?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 4
    This logic is not really solid. If we were to allow zero-sized objects at the same address, it would be logical to declare both `new` and `delete` for such objects as no-ops, i.e. `new` would return some arbitrary address (it's OK, since it is not dereferencible anyway) and `delete` would simply do nothing. – AnT stands with Russia Feb 11 '11 at 15:43
  • @AndreyT - What about things that inherit from the empty items – Flexo Feb 11 '11 at 15:45
  • 1
    I think its not the point. Operator new could return predefined 0x1 for every empty object allocated and delete could do nothing for such address (no data - nothing to alloc - nothing to free). – wonder.mice Feb 11 '11 at 16:02
  • It would be a lot of work for nothing. Also, at least I would be surprised if I created two separate objects and they somehow behaved as one (or... nothing). In my eyes, an empty object is still a distinct object. – Skurmedel Feb 11 '11 at 16:06
  • What would delete do ? Release allocated memory. We have a size of an object, so delete would deallocate 0 memory. Another thing which will delete() do is destructor call, which can be reasonable even for an empty object (i.e. object with no fields). So ye, I don't see any contradiction yet. – Andrew_Lvov Feb 11 '11 at 16:14
3

C++ has (among other things) a rule that says pointers to objects compare equal if and only if the pointers refer to the same object. Under the scenario you propose, this would no longer be true.

There's also quite a bit of code that simply assumes sizeof will also produce a strictly positive result. Jut for example, quite a bit of code uses things like:

#define elements(array) ((sizeof(array)/sizeof(array[0]))

For objects with a size of zero, this would result in 0/0, which is mathematically undefined.

Rather than make changes everywhere else to support one corner case, it was a lot simpler to simply eliminate the corner case so it fit with existing rules.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Example with sizeof is actually a problem of a C++ language implementation, not a fundamental problem. – Andrew_Lvov Feb 11 '11 at 16:17
  • >>C++ has (among other things) a rule that says pointers to objects compare equal if and only if the pointers refer to the same object. Which should this rule be fulfilled ? Btw, where is this rule described ? – Andrew_Lvov Feb 11 '11 at 16:18
  • @Andrew_Lvov: it is described in the standard §5.10.1: `Two pointers of the same type compare equal if and only if they are both null, both point to the same object or function, or both point one past the end of the same array.` – Luc Touraille Feb 11 '11 at 16:26
  • @Andrew_Lvov: It's not really implementation either, but how it's used. One of the most fundamental design guides for C++ has always been that it has to remain compatible with virtually all existing C code, and allowing `sizeof` to yield zero wouldn't fit that at all. – Jerry Coffin Feb 11 '11 at 16:28
1

When you have two pointers to the same object, you can use either to manipulate the object. Result = you can access the object.

However, if you have two objects at the same address, how would you differentiate between them in memory? If you had a pointer to that address, how would you know which object your pointer was pointing to?

Hence the need for different addresses for each object, even if they are empty.

Sagar
  • 9,456
  • 6
  • 54
  • 96
0

Try an analogy.

If you have two cars, and you try to have them occupy the same physical space, you'll have a crash.

If you have two objects and you try to have them occupy the same memory space, you'll also have a crash.

Tony Park
  • 1,247
  • 1
  • 9
  • 14