Topic: Empty Objects


Author: jamshid@ses.com (Jamshid Afshar)
Date: 1995/03/31
Raw View
In article <D5r6ru.68q@tigadmin.ml.com>,
Julian Pardoe LADS LDN X1428 <pardoej@lonnds.ml.com> wrote:
>1) In C and C++ we use an object's address as (a surrogate for) its identity
>and answer the question "Do these two object-referencing expressions reference
>the same object?" by testing the equality of pointers.  (It's an interesting
>point that with multiple inheritance in C++ we've broken the one-to-one
>mapping between addresses and indentity: a single object may have more than
>one address.  Given
>
>    class D: public B1, public B2 {...};
>    D d;
>
>(B1 *) &d != (B2 *) &d yet d is one object, not two!  This has messed up the
>relationship between address and identity -- e.g. it is not necessarily
>true that (D *)(void *)(B2 *)&d == &d, a fact that has tripped up more
>than one programmer whose code I've had to debug.)

If B1 and B2 are unrelated classes, then you simply can't compare
(B1*)&d with (B2*)&d.  (well, you could cast to them to void*'s but
that's very meaningless -- void*'s are not guaranteed and shouldn't be
expect to "work" unless you cast it to the *exact* type it was before
it was converted).  If you mean for B1 and B2 to be related (eg, both
derived from class B), it makes sense that (B1 *) &d != (B2 *) &d.
There's two different B (sub)objects with two different sets of data
members, so they aren't the "same" object.

What I want to know is what ANSI/ISO has said about:

 class Container {};
 class Vector : public Container {
    int a[10];
 }
 class Queue : public Container {
    Vector v;
 // queue implemented as a vector
 };

 Queue q;
 if (q==q.v)  // look, Ma, no casts!
    things_are_very_screwy();

Although sizeof(Container)>0, I don't believe a compiler must reserve
space for it when it is a base class.  I strongly believe that
ANSI/ISO should require that the address of two different objects
should NOT compare equal (when the pointer comparison involves only
standard conversions).  If ANSI/ISO allows q==q.v you can't do things
like maintain a set of all "live" containers by Container::Container()
adding `this' to a static Set<Container*> and safely remove it in
Container::~Container().  Of course, I don't want to see them go
overboard and require that space be reserved for empty base classes in
all situations.

Has ANSI/ISO discussed this matter?

Thanks,
Jamshid Afshar
jamshid@ses.com





Author: pde@zoo.bt.co.uk (Paul D Evans)
Date: 22 Mar 1995 19:13:07 GMT
Raw View
In article 12411@mole-end.matawan.nj.us, mat@mole-end.matawan.nj.us writes:

[stuff deleted]

> The program's `storage' is tied to its `address space.'  If the address
> space is consumed, then storage is consumed even if it is not used.

One way around this is NOT to tie program storage to address space.
That is to have a virtual address space that is mapped to physical
storage via a hardware/software object-address server.  This, of course,
can be done, and already has been done (e.g. Texas), in C++.

As is usually the case in C++, if you need such extravagance: don't
change the language -- just implement it with the language as it
stands.

[more stuff deleted]

---
                      ,')
-__ /\\                /|
  ||  \\   _           ||
 /||__||  < \, '\ /\\  ||        pde@zoo.bt.co.uk
 \||__||  /-||  || ||  ||
  ||  |, (( ||  || ||  ||               "Close this book at once,
_-||-_/   \/\\   \\/   |/   it's full of lies!"
  ||                   (_ _  The Book of Bokannon
                         -






Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 20 Mar 1995 00:07:03 GMT
Raw View
mikeq@primenet.com (Michael Quinlan) writes:

>In article <D5BF2x.LEy@world.std.com> tob@world.std.com (Tom O Breton) writes:
>
>>> If they didn't have unique addresses then there would be no way to delete
>>> them.
>
>>"zero-length" means that it has _no_ _data_ in it. See? No point in
>>actually allocating or deleting it. Nothing in there.
>
>    The point is to execute the destructor. Without a unique address, there is
>    no way to use the delete operator. The delete operator invokes the
>    destructor for the object being deleted.

If new were allowed to return the same non-zero address for multiple
allocations, then presumably you would be allowed to pass the same
address to delete multiple times (and the address would not be invalidated
until it had been deleted as many times as it was allocated).

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Mon, 20 Mar 1995 19:14:17 GMT
Raw View
In article 12411@mole-end.matawan.nj.us, mat@mole-end.matawan.nj.us writes:
>Look more carefully.
>
>The program's `storage' is tied to its `address space.'  If the address
>space is consumed, then storage is consumed even if it is not used.
>
>Each object has a unique address.  (This is part of what it means to
>be an object.)  Thus, each object will consume some part of the address
>space.
>
>Yes, there are tricks that can be played (like using for the address of a
>zero-length object a pointer into the middle of a built-in type object
>like a float or a double) but they just forestall the inevitable.

I can't help feeling that though it makes sense, this argument is pitched
at too low a level.  This is not a question about the implementation of
malloc or memory locations or address spaces but about something more
fundamental.

The fundamental issue is, I believe, that of an object's identity.

1) In C and C++ we use an object's address as (a surrogate for) its identity
and answer the question "Do these two object-referencing expressions reference
the same object?" by testing the equality of pointers.  (It's an interesting
point that with multiple inheritance in C++ we've broken the one-to-one
mapping between addresses and indentity: a single object may have more than
one address.  Given

    class D: public B1, public B2 {...};
    D d;

(B1 *) &d != (B2 *) &d yet d is one object, not two!  This has messed up the
relationship between address and identity -- e.g. it is not necessarily
true that (D *)(void *)(B2 *)&d == &d, a fact that has tripped up more
than one programmer whose code I've had to debug.)

2) There is nothing unreasonable about a class of objects having no other
attributes than their identity.  We might use them as meaning-free labels
for instance.

3) It seems reasonable to require that different objects have different
identities (if that's not a tautology) and that different calls to new
create distinct objects.

Hence the problem...

All this would be true even if C++ didn't use address as a surrogate for
identity.  We can't sensibly argue about what malloc/new should do until
we've solved the underlying theoretical issue.

This isn't to say that at the end of the day (when we've understood the
issues) we might not accept theoretically inconsistent semantics for
pragmatic reasons.

Given the ways I use zero-length objects I'd be quite happy for the
usual rule that different objects have different addresses to be violated
in this case.  I use zero-length objects in certain stylized ways and
object indentity is not an issue.

-- jP --






Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Mon, 20 Mar 1995 19:20:51 GMT
Raw View
In article 0015F45F@primenet.com, mikeq@primenet.com (Michael Quinlan) writes:
>In article <D5BF2x.LEy@world.std.com> tob@world.std.com (Tom O Breton) writes:
>
>>> If they didn't have unique addresses then there would be no way to delete
>>> them.
>
>>"zero-length" means that it has _no_ _data_ in it. See? No point in
>>actually allocating or deleting it. Nothing in there.
>
>    The point is to execute the destructor. Without a unique address, there is
>    no way to use the delete operator. The delete operator invokes the
>    destructor for the object being deleted.

So what?  If the object has no non-static members then the destructor will
necessarily make no accesses to it.  That doesn't stop it doing other things
though.  Thus it's perfectly possible and reasonable to invoke the destructor
for a zero-sized object.

All this remains true even if zero-length objects share an address.  As has
been pointed out by several posters, it is quite easy to come up with schemes
whereby the freeing of this address is a no-op.

-- jP --





Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Mon, 20 Mar 1995 20:05:33 GMT
Raw View
In article 95Mar13160719@physics10.berkeley.edu, matt@physics10.berkeley.edu (Matt Austern) writes:
>In article <D5EJzw.29I@world.std.com> tob@world.std.com (Tom O Breton) writes:
>
>> There are 4 ways to make zero-lengths OK with delete:
>[ suggestions deleted]
>
>Just look at what's going on here, though!  The original idea was that
>zero-length objects should be permitted on the grounds that they were
>only forbidden by an ad hoc special case.
>
>I think it ought to be clear by now that, in fact, it's the other way
>around: if zero-length objects are permitted, then there will have to
>be lots of special case rules (destructors, inheritance, array access)
>to handle them.  Sure, you can do it---it'll be a lot of work, though.
>You'll have to go over every aspect of the language and look at
>whether the existing rules make sense for zero-length objects and, if
>not, make up a new rule that applies to them.
>
>The rule that forbids zero-length objects isn't a gratuitous
>restriction, and getting rid of it doesn't make the language cleaner
>or simpler.  Getting rid of it would make the language far more
>compilcated.
>--
>
>                               --matt

This is a good argument but I don't buy it.  Yes, allowing zero-length
objects might make the language more complex but, as so often, the cure
is worse than the disease.  Not being allowed zero-length arrays makes me
write more complex and error-prone code than I would if I were allowed
them -- even allowing for the fact that the semantics of the address of
a zero-length object are a bit dodgy.  What's more, the work of defining
the standard is done once but millions of people write C/C++ code every day.

Saying "You may have zero-length objects but it is not guaranteed that
the address of such an object will be distinct from the addresses of
all other objects" would not make the language vastly more complicated
but it would make some of my programs a lot less complicated.  And with
some careful analysis it might be possible to come up with an even better
formulation that is still fairly straightforward.

-- jP --

PS: I've always consider the absence of "break" in Pascal a perfect example
of a cure worse than the disease.  Yes, oh trauma!, "break" is a kind of "goto"
but have you seen the horrible loops Pascal programmers have to write, adding
extra variables which they have to initialize, writing while-loops where they
want a for-loop and then adding some of the most complex, hard-to-understand
conditions that I have ever had the misfortune to try and understand.
(In Xerox's language Mesa there are even more loopy gotos, called loop-exits:
they make it even easier to write clear code.)







Author: mat@mole-end.matawan.nj.us
Date: Wed, 15 Mar 1995 11:59:58 GMT
Raw View
In article <D5BF2x.LEy@world.std.com>, tob@world.std.com (Tom O Breton) writes:
> stidev@gate.net (Solution Technology) writes:
> > : I suspect that "zero-length objects have no data so it's irrelevant what
> > : the 'address' of the (non-) data is." may summarize the issue. I find it
> > : difficult to see how one may need an address without caring what's _at_
> > : the address (if not right away, then eventually). But I could be wrong.
> >
> >
> > If they didn't have unique addresses then there would be no way to delete
> > them.
>
> "zero-length" means that it has _no_ _data_ in it. See? No point in
> actually allocating or deleting it. Nothing in there.

Not quite.

Even though it has nothing `in' it, it exists.  Objects of that type
have a lifetime, a beginning and an end.  Their constructors and
destructors can do things.

You are still in the vale of pre-object programming.
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: mat@mole-end.matawan.nj.us
Date: Wed, 15 Mar 1995 12:05:46 GMT
Raw View
In article <DOUG.95Mar13111827@monet.ads.com>, doug@monet.ads.com (Doug Morgan) writes:
> In article <1995Mar11.125525.21105@mole-end.matawan.nj.us> mat@mole-end.matawan.nj.us writes:
> > ...
> > Let's try this again: the requirement that every (complete) object, empty
> > or otherwise, have a unique address means that every object will result
> > in the loss of some of the program's address space to every object.  This
> > is not the result of `artifice.'  It follows directly and necessarily
> > from the more fundamental definition (that of an object) in the language.

> The ARM defines an object as a "region of storage."  Ignoring how
> deficient this definition is, it certainly doesn't directly and
> necessarily imply a non-zero length region of storage.  Now supposing
> the WP has fixed up the definition, how does the new fundamental
> definition (if it exists) imply that objects have positive length
> without simply falling back on "that is just the way we want it"?

> > If that isn't a `lead-pipe' argument, I'm not sure what is.

> Without spelling out the "fundamental definition" for the
> non-committee members, it feels more like PVC.

Look more carefully.

The program's `storage' is tied to its `address space.'  If the address
space is consumed, then storage is consumed even if it is not used.

Each object has a unique address.  (This is part of what it means to
be an object.)  Thus, each object will consume some part of the address
space.

Yes, there are tricks that can be played (like using for the address of a
zero-length object a pointer into the middle of a built-in type object
like a float or a double) but they just forestall the inevitable.
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 16 Mar 1995 18:11:42 GMT
Raw View
In article <D5Ev84.4E@ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John
Max Skaller) writes:

|>  Whether in fact this is OK depends on the exact wording.
|> For example, an implementation may return '0xffffffff' for all zero
|> length objects and _count_ each allocation an deallocation. When
|> the count was positive, the address is valid, when the count is zero,
|> the address is invalidated to force an error on any use.

Or... the implementation simply never invalidates an address (in the
sense that you mean).  This is the current situation with most systems
anyway.

More generally, requiring new to return a distinct address for each
call is independent of the minimum size of an object.  You could allow
0 length objects, and still require new to always return a unique
address.  (In this case, objects that are sub-objects of another
object, or objects that are on the stack or heap, might not have
distinct addresses.)
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: doug@monet.ads.com (Doug Morgan)
Date: 17 Mar 1995 00:13:25 GMT
Raw View
In article <1995Mar15.120546.12411@mole-end.matawan.nj.us> mat@mole-end.matawan.nj.us writes:
> In article <DOUG.95Mar13111827@monet.ads.com>, doug@monet.ads.com (Doug Morgan) writes:
> > In article <1995Mar11.125525.21105@mole-end.matawan.nj.us> mat@mole-end.matawan.nj.us writes:
> > > ...
> > > Let's try this again: the requirement that every (complete) object, empty
> > > or otherwise, have a unique address means that every object will result
> > > in the loss of some of the program's address space to every object.  This
> > > is not the result of `artifice.'  It follows directly and necessarily
> > > from the more fundamental definition (that of an object) in the language.
>
> > The ARM defines an object as a "region of storage."  Ignoring how
> > deficient this definition is, it certainly doesn't directly and
> > necessarily imply a non-zero length region of storage.  Now supposing
> > the WP has fixed up the definition, how does the new fundamental
> > definition (if it exists) imply that objects have positive length
> > without simply falling back on "that is just the way we want it"?
>
> > > If that isn't a `lead-pipe' argument, I'm not sure what is.
>
> > Without spelling out the "fundamental definition" for the
> > non-committee members, it feels more like PVC.
>
> Look more carefully.
>
> The program's `storage' is tied to its `address space.'  If the address
> space is consumed, then storage is consumed even if it is not used.

OK, I'll identify `storage' with `address space.'

> Each object has a unique address.  (This is part of what it means to
> be an object.)  Thus, each object will consume some part of the address
> space.

Which came first, unique addresses or no empty objects?  No empty
objects implies some unique addresses (probably the ones you were
thinking of), so the argument becomes "there can't be empty classes in
C++ because we declared that there can't be any."  The statement is
completely true (and therefore can be forcibly argued), but is not
particularly persuasive.

Also, objects and subobjects, arrays and first elements, and maybe
other stuff can share pointer values.  Also, I thought there were no
guarantees in C++ (results are implementation dependent) about the
comparison of pointers to objects not in the same object, union or
array (or one past the end of the array).  I'm not sure what, if
anything, this really says about addresses of *objects*, but it
doesn't seem to back up the idea that each object must have a unique
address.

I think that not allowing empty objects is reasonable.  However, the
decision looks to be largely pragmatic, based on weighing perceived
likelihoods of language acceptance, not because it "has" to be that
way.

> Yes, there are tricks that can be played (like using for the address of a
> zero-length object a pointer into the middle of a built-in type object
> like a float or a double) but they just forestall the inevitable.

Yeah, these tricks probably fit in with the comment about subobjects
and array elements.  In all, I suspect empty objects are just a bit
too dainty for C++, so the inevitable result is that they will remain
banned.

Doug
----------
Doug Morgan, doug@ads.com
Booz-Allen & Hamilton
1500 Plymouth St.
Mountain View, CA 94043-1230
     (415) 960-7444
FAX: (415) 960-7500
----------




Author: tony@online.tmx.com.au (Tony Cook)
Date: Fri, 17 Mar 1995 02:57:26 GMT
Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:

:  Whoa! There is a distinction between the "length" of an object,
: and whether or not it has a distinct address.

:  The requirements of "new" are _at least_ that a returned
: pointer be a valid address. Such an address can be copied.

Doesn't the WP currently require new to return a unique address,
even for zero-length objects (see [basic.stc.dynamic.allocation]
paragraph 2)?

--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com




Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Tue, 14 Mar 1995 12:56:01 GMT
Raw View
In article 4xM@world.std.com, tob@world.std.com (Tom O Breton) writes:
>I suspect that "zero-length objects have no data so it's irrelevant what
>the 'address' of the (non-) data is." may summarize the issue. I find it
>difficult to see how one may need an address without caring what's _at_
>the address (if not right away, then eventually). But I could be wrong.

You're right that one doesn't care what's at the address: if I have a zero-
length array I'll look at all 0 elements -- no problem!

However, that doesn't mean that one doesn't care about the identity of the
object (and the fact that that identity should be distinct from the identity
of other objects).

It's the fact that one wants pointers to different objects to compare
differently that makes zero-sized objects problematic.

I suspect that the uses of zero-length objects are such that this is not
a problem in practice, but it's hard to say what uses for them other
people might think of.

-- jP --






Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Tue, 14 Mar 1995 13:00:30 GMT
Raw View
In article 1dsb@tequesta.gate.net, stidev@gate.net (Solution Technology) writes:
>Tom O Breton (tob@world.std.com) wrote:
>
>: I suspect that "zero-length objects have no data so it's irrelevant what
>: the 'address' of the (non-) data is." may summarize the issue. I find it
>: difficult to see how one may need an address without caring what's _at_
>: the address (if not right away, then eventually). But I could be wrong.
>
>
>If they didn't have unique addresses then there would be no way to delete
>them.
>
>Ken Walter
>

Not necessarily true : I could use the same invalid address for all zero-length
objects and make deletion of this address a no-op.

In any case, this is a run-time library problem.  The problem of zero-length objects
having different addresses occurs even if we don't have malloc/new.

    struct Empty {};
    Empty a, b;

The argument is that &a must not equal &b or one of the basic rules of C/C++ is
violated.

-- jP --





Author: ccwf@hegel.klab.caltech.edu (Charles Fu)
Date: 16 Mar 1995 00:14:11 GMT
Raw View
In article <D5Dwt5.GKJ@ucc.su.oz.au>,
John Max Skaller <maxtal@Physics.usyd.edu.au> wrote:
> I don't agree with your argument. The requirement that
>every (complete) object have a unique address does NOT follow
>from the definition of what an object is.

> It IS the definition of what an object is. That is,
>it is one of the AXIOMS of the kind "object".

The subject of zero-sized objects reminds me strongly of the treatment of
objects allocated using "new some_type[0]".  Such pointers must be also
unique to comply with the definition of an object.  I would think that,
were zero-size objects to be allowed, it would be a "good thing" for
addresses of zero-size objects and the pointers to objects returned by
new(0) to behave similarly.

-ccwf




Author: tob@world.std.com (Tom O Breton)
Date: Sat, 11 Mar 1995 22:34:14 GMT
Raw View
pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428) writes:
> PS: I never saw much discussion of the issues with zero-sized objects
> so if someone knowledgeable on the topic would care to mail be a quick
> summary I'd be most grateful.

Nor I. The issue has come up on the group before but not as heavily.

John Skaller, who is brilliant and is usually right, contends that
having a unique address is an indispensable part of being an object.

I suspect that may be wrong. It's clear that for _some_ purposes, having
zero length removes the need for a unique or even meaningful address. I
think it may remove the need in all cases, but I eagerly await
counterexamples.

I suspect that "zero-length objects have no data so it's irrelevant what
the 'address' of the (non-) data is." may summarize the issue. I find it
difficult to see how one may need an address without caring what's _at_
the address (if not right away, then eventually). But I could be wrong.


> In my experience, protecting the programmer from himself usually means
> forcing him/her into all sorts of contortions to get around the
> restriction.  (I don't know if it's realy true of Ada but when I used to
> read Ada Letters I got the feeling that 50% of the articles were "How to
> fool the compiler into allowing you to do this or that reasonable
> thing."

Yes. It's the bad side to high-level languages: Things that make you
bang your head against a wall saying "I know what I want to do, why
won't the compiler _just_ let me do it!"

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: stidev@gate.net (Solution Technology)
Date: 11 Mar 1995 22:41:48 GMT
Raw View
Tom O Breton (tob@world.std.com) wrote:

: I suspect that "zero-length objects have no data so it's irrelevant what
: the 'address' of the (non-) data is." may summarize the issue. I find it
: difficult to see how one may need an address without caring what's _at_
: the address (if not right away, then eventually). But I could be wrong.


If they didn't have unique addresses then there would be no way to delete
them.

Ken Walter





Author: tob@world.std.com (Tom O Breton)
Date: Sun, 12 Mar 1995 06:52:08 GMT
Raw View
stidev@gate.net (Solution Technology) writes:
> : I suspect that "zero-length objects have no data so it's irrelevant what
> : the 'address' of the (non-) data is." may summarize the issue. I find it
> : difficult to see how one may need an address without caring what's _at_
> : the address (if not right away, then eventually). But I could be wrong.
>
>
> If they didn't have unique addresses then there would be no way to delete
> them.

"zero-length" means that it has _no_ _data_ in it. See? No point in
actually allocating or deleting it. Nothing in there.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: mat@mole-end.matawan.nj.us
Date: Sat, 11 Mar 1995 12:55:25 GMT
Raw View
In article <3jkudl$mqj@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:
> mat@mole-end.matawan.nj.us wrote:
> : In article <3jfik9$m6b@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:

> : In any case, the rule is neither silly nor unnatural; it is quite organic,
> : coming from the basic requirement that every object, empty or not, have
> : a unique address.  ...
 ...
>          ...  People have understandably argued
> against artificial, special case rules such as empty structs, name
> hiding, and the prohibition of non-constant references to temporaries.
> I have yet to see a "lead-pipe" argument in support of any of these
> monstrosities and find their presence difficult to comprehend,
> justify, or digest.

I hope I'm not misrepresenting you by what I have elided.

You may notice that I used the word `organic' and then explained how
there is a basic guarantee in the language's definition of an object.

You then claim that there is an artifical special-case rule against empty
structs.

Let's try this again: the requirement that every (complete) object, empty
or otherwise, have a unique address means that every object will result
in the loss of some of the program's address space to every object.  This
is not the result of `artifice.'  It follows directly and necessarily
from the more fundamental definition (that of an object) in the language.

If that isn't a `lead-pipe' argument, I'm not sure what is.

As far as the name hiding, someone else pointed to Stroustrup's discussion
in 3.5.3 on p. 77 of D&E.  Very simply, if you think you are making a
call to (a member of) Derived and you accidentally call (a member of) Base
instead, and if Base and Derived are not _designed_ for that behavior,
you can end up with half your state changes occurring to Base and half to
Derived--_not_ what you wanted!  You can say that the `component' or
`feature' of the base class that is made available for use by the derived
class is the _function_ rather than the _name_ (the _name_ is overloaded,
the _function_ is not).

With the new model of `class as enhanced namespace' it's possible to use
a  using  declaration to `promote' all the base class versions of a name
into the derived class's namespace.  This is appropriate for the case
you describe, in which the _name_ and not (just) the _function_ is part of
the interface to the derived class.

Given  If A Then B  and also given  A  , we cannot have  Not B .  That
we cannot is not an extra constraint; it is a logical necessity in the
system we have adopted.
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: mikeq@primenet.com (Michael Quinlan)
Date: Sun, 12 Mar 1995 14:19:17 MST
Raw View
In article <D5BF2x.LEy@world.std.com> tob@world.std.com (Tom O Breton) writes:

>> If they didn't have unique addresses then there would be no way to delete
>> them.

>"zero-length" means that it has _no_ _data_ in it. See? No point in
>actually allocating or deleting it. Nothing in there.

    The point is to execute the destructor. Without a unique address, there is
    no way to use the delete operator. The delete operator invokes the
    destructor for the object being deleted.

+---------------------------------+
| Michael Quinlan                 |
| mikeq@primenet.com              |
| http://www.primenet.com/~mikeq/ |
+---------------------------------+





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Mon, 13 Mar 1995 14:51:15 GMT
Raw View
In article <D5As12.4xM@world.std.com>, Tom O Breton <tob@world.std.com> wrote:
>pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428) writes:
>> PS: I never saw much discussion of the issues with zero-sized objects
>> so if someone knowledgeable on the topic would care to mail be a quick
>> summary I'd be most grateful.
>
>Nor I. The issue has come up on the group before but not as heavily.
>
>John Skaller, who is brilliant and is usually right, contends that
>having a unique address is an indispensable part of being an object.
>
>I suspect that may be wrong. It's clear that for _some_ purposes, having
>zero length removes the need for a unique or even meaningful address. I
>think it may remove the need in all cases, but I eagerly await
>counterexamples.

 But if you read very carefully what you just said, you may
see that we do not necessarily have a dispute.

 Suppose you say

 class X {};
 X* x1 = new X;
 X* x2 = new X;

and X is an empty class and we permit x1==x2. Then I say that
because there are no unique addresses here, there are no
objects. That is _not_ to say the above declarations are
invalid, just that in this case "new" is not creating an object.

 Now consider:

 class Y : X { int a; };
 Y * y = new Y; // an object, non-zero length
 X * x = y;

What does "y" denote? It denotes two things "somehow": the object
*y, and also a _base class subobject_ of type X. Which
is not an object.

IMHO a base class subobject isn't an object in the first place.
Now consider:

 class Z {
  X x;
  int i;
 };

Here the _member subobject_ x might have zero length. Which shows
again that a member subobject isn't necessarily an object.

In my _opinion_ "new" should return a unique address.  And

 *new T

is an object. This does not _necessarily_ mean that member
and base _sub_ objects have to have unique addresses, because
neither is _necessarily_ an object in the first place.
In fact, I tend to think

 a) a member subobject (or array element) is _always_
 an object (and has non-zero "length")

 b) base subobjects are _never_ objects (they're "views"
 of objects) and so one cannot rely on their addresses
 being unique.

>I suspect that "zero-length objects have no data so it's irrelevant what
>the 'address' of the (non-) data is." may summarize the issue. I find it
>difficult to see how one may need an address without caring what's _at_
>the address (if not right away, then eventually). But I could be wrong.

 Its the other way around. It is clearly useful to
be able to create unique addresses without these addresses
denoting "objects" with values.

 It is also clearly useful to know, if it is the case,
that base subobjects always have unique addresses -- in fact
this is a critically important issue for containers of
pointers to abstract classes. In particular, for a container
such as the STL "set" class.

 Consider:

 class E {};
 class L : E {};
 class R : E {};
 class D : L, R {};

If we have a set of E*, it is important to know whether given

 D d;
 E* el = (L*) &d;
 E* er = (R*) &d;
 set<E*> eset;
 eset.insert(e1);
 eset.insert(e2);

eset contains 1, or 2, members. More especially, IF E had been
abstract, then no E* can denote a member subobject, and so
if we also know base subobjects of the same object have unique addresses,
the answer to the question above would be

 "always 2 members".

That is more definite that "maybe 1 and maybe 2, depending on the
implementation".

>> In my experience, protecting the programmer from himself usually means
>> forcing him/her into all sorts of contortions to get around the
>> restriction.  (I don't know if it's realy true of Ada but when I used to
>> read Ada Letters I got the feeling that 50% of the articles were "How to
>> fool the compiler into allowing you to do this or that reasonable
>> thing."
>
>Yes. It's the bad side to high-level languages: Things that make you
>bang your head against a wall saying "I know what I want to do, why
>won't the compiler _just_ let me do it!"

 I don't agree this is a necessary attribute of high level
languages. Either you fail to understand the coherent framework
presented by the language, or the framework isn't in fact
coherent.

 In the case of C++ there are lots of things, in my
opinion, which are not very well designed. Many are
directly due to it's C heritage, others not.


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: doug@monet.ads.com (Doug Morgan)
Date: 13 Mar 1995 19:18:27 GMT
Raw View
In article <1995Mar11.125525.21105@mole-end.matawan.nj.us> mat@mole-end.matawan.nj.us writes:
> ...
> Let's try this again: the requirement that every (complete) object, empty
> or otherwise, have a unique address means that every object will result
> in the loss of some of the program's address space to every object.  This
> is not the result of `artifice.'  It follows directly and necessarily
> from the more fundamental definition (that of an object) in the language.

The ARM defines an object as a "region of storage."  Ignoring how
deficient this definition is, it certainly doesn't directly and
necessarily imply a non-zero length region of storage.  Now supposing
the WP has fixed up the definition, how does the new fundamental
definition (if it exists) imply that objects have positive length
without simply falling back on "that is just the way we want it"?

> If that isn't a `lead-pipe' argument, I'm not sure what is.

Without spelling out the "fundamental definition" for the
non-committee members, it feels more like PVC.

Doug
----------
Doug Morgan, doug@ads.com
Booz-Allen & Hamilton
1500 Plymouth St.
Mountain View, CA 94043-1230
     (415) 960-7444
FAX: (415) 960-7500
----------




Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Mon, 13 Mar 1995 15:10:17 GMT
Raw View
In article <1995Mar11.125525.21105@mole-end.matawan.nj.us>,
 <mat@mole-end.matawan.nj.us> wrote:
>
>Let's try this again: the requirement that every (complete) object, empty
>or otherwise, have a unique address means that every object will result
>in the loss of some of the program's address space to every object.  This
>is not the result of `artifice.'  It follows directly and necessarily
>from the more fundamental definition (that of an object) in the language.
>

 I don't agree with your argument. The requirement that
every (complete) object have a unique address does NOT follow
from the definition of what an object is.

 It IS the definition of what an object is. That is,
it is one of the AXIOMS of the kind "object".

 There is no requirement that an object have non-zero
length. The requirement is that

 sizeof(T)

be non-zero, for any T which _can_ be placed in an array.
We deduce this from the axiom and the requirement
that the members of an array are (distinct) objects:

PROOF:

 T a[n];
 T *t0 = a;
 T *t1 = t0+1;
 (char*)(void*) t1 == ((char*)(void*)t2) + sizeof(T); // defn

By AXIOM, t1 != t2. Assume sizeof(T)==0. Then

 (char*)(void*) t1 == (char*)(void*) t2 // since t+0 == t
 t1 == t2 // by hand waving
 ## contradiction

Hence sizeof(T) !=0.

NOTE that for an abstract class we do NOT know if sizeof(T) ==0
or not because no abstract class can be a array member subobject.

It is not clear if base or member subobjects are complete
objects or not.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: doug@monet.ads.com (Doug Morgan)
Date: 13 Mar 1995 18:57:57 GMT
Raw View
In article <mikeq.136.0015F45F@primenet.com> mikeq@primenet.com (Michael Quinlan) writes:
> In article <D5BF2x.LEy@world.std.com> tob@world.std.com (Tom O Breton) writes:
>
> >> If they didn't have unique addresses then there would be no way to delete
> >> them.
>
> >"zero-length" means that it has _no_ _data_ in it. See? No point in
> >actually allocating or deleting it. Nothing in there.
>
>     The point is to execute the destructor. Without a unique address, there is
>     no way to use the delete operator.

delete obj;

What's to stop anyone from using the delete operator?  What difference
does it make if obj is empty or at the same address as another object?
If obj has a virtual destructor, the language has to guarantee that
the correct destructor is called.  Therefore, whenever there is the
opportunity of putting an object of different type (also with a
virtual destructor) "on top" of obj, the compiler would have to make
that particular obj effectively take up a bit of space.  In other
cases, it wouldn't.  For example, any number of empty objects with
non-virtual deletes could be jammed into one address without any
problem.

Also (and largely irrelevant), delete ought to follow a new, and most
default new-s will add a few bytes around the object and thereby
ensure a unique address (as far as any pointer is C++ is ever
guaranteed to be unique, which few are).  Of course, non-default new-s
might do something else.

> The delete operator invokes the
>     destructor for the object being deleted.

So?  It would continue to do just that for an empty object too.

C compatibility and a preference for one way of handling boundary
cases are probably the best arguments for no-empty-objects.  This
reflects the fact(?) that C++ was (and is) largely built on judgement
calls of what Joe programmer might prefer.  The original assessment of
Joe seems to have been (probably quite correctly) that Joe thought C
compatibility was worth a design with a few strange special cases.

Doug
----------
Doug Morgan, doug@ads.com
Booz-Allen & Hamilton
1500 Plymouth St.
Mountain View, CA 94043-1230
     (415) 960-7444
FAX: (415) 960-7500
----------




Author: tob@world.std.com (Tom O Breton)
Date: Mon, 13 Mar 1995 23:31:08 GMT
Raw View
mikeq@primenet.com (Michael Quinlan) writes:
>     The point is to execute the destructor. Without a unique address, there is
>     no way to use the delete operator. The delete operator invokes the
>     destructor for the object being deleted.

There are 4 ways to make zero-lengths OK with delete:

0:  The delete operator for 0's are understood to be non-functional, as
if

        my_class:: operator delete ( void * ) { };

had been written. This one is most runtime efficient.

1:  The new operator for 0's returns a magic value such as NULL, and the
delete operator does not work on that value.

This one is sloppiest, but works. I don't recommend it.

2:  delete is illegal on zero-lengths. dtor can be called by hand, if
there's any point doing it. Bear in mind that "delete" had to be called
by hand here too. Easier to implement, clumsier to program.

3:  Let the allocator work normally, relying on the fact that it also
allocates a header (And often an entire paragraph minimum). Basically
reasoning that a user who _allocates_ a zero-length ob (as opposed to
making it on the stack or as part of another) is lost to efficiency
anyways. Easiest to implement: No work at all. Least efficient.

This one seems to have a gotcha but really IMO doesn't: Some allocators
like freelist allocators do not add headers. But in my experience
there's a minimum size, usually sizeof( void *). The only way it can
fail is if it holds some header data but does _not_ group it with the
objects.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: tob@world.std.com (Tom O Breton)
Date: Mon, 13 Mar 1995 23:31:05 GMT
Raw View
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>         But if you read very carefully what you just said, you may
> see that we do not necessarily have a dispute.
>
>         Suppose you say
>
>         class X {};
>         X* x1 = new X;
>         X* x2 = new X;
>
> and X is an empty class and we permit x1==x2. Then I say that
> because there are no unique addresses here, there are no
> objects. That is _not_ to say the above declarations are
> invalid, just that in this case "new" is not creating an object.

OK, that seems to be consistent. I have no disagreement with that.

>         It is also clearly useful to know, if it is the case,
> that base subobjects always have unique addresses -- in fact
> this is a critically important issue for containers of
> pointers to abstract classes. In particular, for a container
> such as the STL "set" class.
>
>         Consider:
>
>         class E {};
>         class L : E {};
>         class R : E {};
>         class D : L, R {};

Something about that example seems off. That would require virtual
derivation of L and R, which would mean there was only 1 E in D anyways.

So I'm trying to see the sense in which you have 2 E's. If it's only 1,
then your example has a simple answer, "always 1 member".

Is D a composition of L and R, both with normal derivation? Then if
they're both substantive, the 2 E's can have different addresses within
D. The only way they can miss is if (I'll assume L comes first) E is
last in L and first in R. A rule like "in a substantive class,
zero-length elements' addresses are inside the object, not at the end
(which might belong to a different substantive object)." would save it.

If L and R are empty too, then D is entirely empty, leading back to the
argument that there's no data to identify in the first place.

If L and R are empty but D has other members, _then_ the E addresses
could be different or the same depending on implementation. _Should_ E
be able to give out different members and rely on unique addresses?

Another objection I have is to the usefulness of any container of empty
objects. One can't use polyporphism, otherwise there'd be data of some
sort in the object, and then they'd have non-zero size. So one is
limited to the data in the objects themselves, which is nothing, so why
store and retrieve it?

The main thing that is nagging me about 0-length obs is not that any
particular issue looks bad, but that it may require a plethora of rules
to handle all the issues.

>         I don't agree this is a necessary attribute of high level
> languages. Either you fail to understand the coherent framework
> presented by the language, or the framework isn't in fact
> coherent.

To clarify, I didn't mean that it is a neccessary attribute of high
level languages, I just meant that it is a frequent problem in them.


        Tom     "RFD: comp.std.c++.empty-objects"

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: matt@physics10.berkeley.edu (Matt Austern)
Date: 14 Mar 1995 00:07:18 GMT
Raw View
In article <D5EJzw.29I@world.std.com> tob@world.std.com (Tom O Breton) writes:

> There are 4 ways to make zero-lengths OK with delete:
[ suggestions deleted]

Just look at what's going on here, though!  The original idea was that
zero-length objects should be permitted on the grounds that they were
only forbidden by an ad hoc special case.

I think it ought to be clear by now that, in fact, it's the other way
around: if zero-length objects are permitted, then there will have to
be lots of special case rules (destructors, inheritance, array access)
to handle them.  Sure, you can do it---it'll be a lot of work, though.
You'll have to go over every aspect of the language and look at
whether the existing rules make sense for zero-length objects and, if
not, make up a new rule that applies to them.

The rule that forbids zero-length objects isn't a gratuitous
restriction, and getting rid of it doesn't make the language cleaner
or simpler.  Getting rid of it would make the language far more
compilcated.
--

                               --matt




Author: tob@world.std.com (Tom O Breton)
Date: Tue, 14 Mar 1995 06:08:44 GMT
Raw View
matt@physics10.berkeley.edu (Matt Austern) writes:
> Just look at what's going on here, though!  The original idea was that
> zero-length objects should be permitted on the grounds that they were
> only forbidden by an ad hoc special case.
>
> I think it ought to be clear by now that, in fact, it's the other way
> around: if zero-length objects are permitted, then there will have to
> be lots of special case rules (destructors, inheritance, array access)
> to handle them.  Sure, you can do it---it'll be a lot of work, though.

Yes, I'm starting to agree. That's what I meant in the other message
when I said:

I myself write:
> The main thing that is nagging me about 0-length obs is not that any
> particular issue looks bad, but that it may require a plethora of rules
> to handle all the issues.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Tue, 14 Mar 1995 03:33:40 GMT
Raw View
In article <D5EJzw.29I@world.std.com>, Tom O Breton <tob@world.std.com> wrote:
>mikeq@primenet.com (Michael Quinlan) writes:
>>     The point is to execute the destructor. Without a unique address, there is
>>     no way to use the delete operator. The delete operator invokes the
>>     destructor for the object being deleted.
>
>There are 4 ways to make zero-lengths OK with delete:

 Whoa! There is a distinction between the "length" of an object,
and whether or not it has a distinct address.

 The requirements of "new" are _at least_ that a returned
pointer be a valid address. Such an address can be copied.

 The use of delete _releases_ the implementation from
any constraints on the use of the address. So copying the address
may cause your hard disk to be wiped.

 Actually, the requirement is that the _particular_ value
returned by new may not be copied after that value is deleted.

 Two _distinct_ values might be returned by two new expressions,
which still compare equal, and deleting one does not prevent the
other being used. Deleting both would.

 Whether in fact this is OK depends on the exact wording.
For example, an implementation may return '0xffffffff' for all zero
length objects and _count_ each allocation an deallocation. When
the count was positive, the address is valid, when the count is zero,
the address is invalidated to force an error on any use.
--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: tmurphy@panix.com (Timothy Murphy)
Date: 9 Mar 1995 15:56:53 -0500
Raw View
Jason Merrill (jason@cygnus.com) wrote:
: >>>>> Timothy Murphy <tmurphy@panix.com> writes:

: >    Why is everyone so concerned with placing empty objects?  Writing
: > down an empty object is by definition useless.

: Not at all.

: class CriticalSect {
:   CriticalSect () { /* disable interrupts */; }
:   ~CriticalSect () { /* enable interrupts */; }
: };

: void foo ()
: {
:   CriticalSect dummy;
:   ....
: }

: You may not agree with this programming style, but you can hardly claim
: that it is "by definition" useless.

: Jason

  Au contraire, I love that programming style and use it all the time.
But does a "CriticalSect" object need a unique address to make this idiom
work?  If it does, is it so awful to jam an "int" in there somewhere?

---tim




Author: tob@world.std.com (Tom O Breton)
Date: Wed, 8 Mar 1995 20:32:01 GMT
Raw View
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>         If each member and base has non-zero size, then
> there is a very very very important guarrantee of a 1-1 relationship
> between objects/subobjects and pointer addresses.
>
>         This identity property is absolutley fundamental
> to object oriented programming.

I'm not sure what that buys you in the zero-length case. With
substantive classes there are idioms like:

        if( &the_other == this )
                {
                //don't bother assigning, or whatever.
                return;
                }

but why would that still matter without data to assign to?

> However, cases where [pointer uniqueness] matters are rare, whereas the
> savings of optimisations may not be. The question really
> is whether the rigid identity guarrantee is worth it.

IMO the important thing is not so much that it's rare, but that it's
easy to insure it where needed:

        char    dummy;

Or include that in an obj_with_unique_address class template, to handle
derivation too.

> Of course sizeof(X) cannot be zero or an array of X would
> not be addressable... although it is hard to see how that
> could matter (since all X values would be equal anyhow :-)

It could matter for orthagonality. But it's pretty tenuous: If you have
a macro or template that defines an array of (type) and you feed it a
zero-length type, you don't need a special case. This would obviously be
very rare and marginal.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: jason@cygnus.com (Jason Merrill)
Date: 08 Mar 1995 20:22:11 GMT
Raw View
>>>>> Timothy Murphy <tmurphy@panix.com> writes:

>    Why is everyone so concerned with placing empty objects?  Writing
> down an empty object is by definition useless.

Not at all.

class CriticalSect {
  CriticalSect () { /* disable interrupts */; }
  ~CriticalSect () { /* enable interrupts */; }
};

void foo ()
{
  CriticalSect dummy;
  ....
}

You may not agree with this programming style, but you can hardly claim
that it is "by definition" useless.

Jason




Author: tony@online.tmx.com.au (Tony Cook)
Date: Wed, 8 Mar 1995 23:10:48 GMT
Raw View
Tom O Breton (tob@world.std.com) wrote:
: maxtal@Physics.usyd.edu.au (John Max Skaller) writes:

: > Of course sizeof(X) cannot be zero or an array of X would
: > not be addressable... although it is hard to see how that
: > could matter (since all X values would be equal anyhow :-)

: It could matter for orthagonality. But it's pretty tenuous: If you have
: a macro or template that defines an array of (type) and you feed it a
: zero-length type, you don't need a special case. This would obviously be
: very rare and marginal.

(I may misunderstand you here...)

It does matter for pointers to such a type:
 T *p1, *p2;
 p1 = ...; p2 = ...; // point into same array
 int distance = p2 - p1; // !! divide by zero? or just undefined
--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com




Author: pardoej@lonnds.ml.com (Julian Pardoe LADS LDN X1428)
Date: Fri, 10 Mar 1995 12:50:25 GMT
Raw View
In article 3l2@mars.worldlinx.com, joshua@oncomdis.on.ca (joshua) writes:
>What would be the values of the 'this pointers' of the empty objects?
>
>If they don't hold any memory, then should this==NULL?  Does this have
>any bearing on your argument?

Since an empty object has no members no operations will be performed
on it and this will never be dereferenced so the value of this is
immaterial.

As I understand it, the only issue is that pointers to different objects
ought to be different and if sizeof (Empty) == 0 we might find
that if we write

    Empty x;
    Thing y;

then (void *)&x == (void *)&y.  Likewise

    Empty *px = new Empty;
    Thing *py = new Thing;

might give (void *)px == (void *)py.

Personally I'd rather be able to have empty objects and arrays and live with
this problem than not be able to have empty objects/array.

In any case, there is a partial solution: allow X such that sizeof (x) == 0 but say
that (in C terms) every invocation of malloc must return a value different from
all other values returned by malloc (and not yet passed to free) even where 0 bytes
of memory are requested.  Likewise, the compiler could be required to insert
padding before an object that will follow in memory after a zero-sized object.

This my declarations would translate to
    _x:
        bss 0
        bss n // padding, where n is chosen to preserve alignment
    _y:
 bss sizeof (Thing)

Note that I didn't say "after an object of zero size" because I don't want any
padding at the end of a struct containing a zero-length array.

There might still be some anomalous cases (e.g,
    struct { int length; char data[0]; } x;
    char y;
does x->data==&y?  The padding rule gets complex!) but in practice it should be enough
to ensure that every object of type Empty (whether new'ed or a named variable)
has a different address.

-- jP --

would result in





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 10 Mar 1995 18:18:59 GMT
Raw View
The decision on empty objects is a trade-off: efficiency versus
convenience.

In general, C++ was carefully designed to avoid "distributed fat" -
paying for some feature that you don't use.  The decision to give empty
structs non-zero size is an unfortunate exception.  The principle that
you shouldn't have to pay for something unless you use it is a good
one, IMHO.

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: alindbac@sw.seisy.abb.se (Anders Lindback)
Date: 10 Mar 1995 08:56:22 GMT
Raw View
In article <3jfik9$m6b@panix3.panix.com>,
Timothy Murphy <tmurphy@panix.com> wrote:
>
>Empty Structures Should Really be Empty.
>
>Timothy S. Murphy   5 March 1995.

>  [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
>even if the object has no data members (or implicit vptrs).  I propose
>the abolition of this rule.

The problem this rule fixes is object identification. How do you distinguish
two pointers to different instances of the same class, if they do not reside
in different memory areas. Thus this requires that the size of the
object to be at least 1. Also what shall new return when a class has zero
size? NULL ?

>   The ARM, in one of its rare moments of utter stupidity, offers the
>following in support of this rule [ARM 9, introduction]: "Empty classes
>can be used as place holders during program development.  In particular,
>an empty class is sometimes used as a base class where the programmer
>suspects that two classes have something in common but hasn't yet
>determined exactly what."  Heh, heh.  1) Is it so onerous to put



>an "int" (or a virtual destructor) into an object if one really wishes
>it to be nonempty?  2) Should we warp the language so unnecessarily in the
>support of ill-conceived programs that by definition will be thrown away?
>A base class without a single method?  Come on ...

On the other hand if this is a pure virtual class this rule does not
hinder the compiler to give it zero memory since the problem can not
occur. All classes that inherit from this abstract class will then not
get any extra size, because of this rule.

>   Empty base classes provide an obvious means of namespace management
>that is useful at least until real namespace implementations become
>available, and maybe even after that.

The argument about namespaces is no good since we are talking about a future
standard and namespaces will be supported in a this standard. The standard
should not bother to support certain paradigms becauee they where used
before the standard was finished. The effort of changing all these classes
into namespaces is small. The overhead of the extra byte for these classes
is also small. Take your pick. If you had not read the standard I suspect you
had not even been observant enough to even notice the extra bytes used by the
program because of this rule.

Anders





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Wed, 8 Mar 1995 03:36:45 GMT
Raw View
In article <3ji375$4h7@panix3.panix.com>,
Timothy Murphy <tmurphy@panix.com> wrote:
>Jason Merrill (jason@cygnus.com) wrote:
>: >>>>> Timothy Murphy <tmurphy@panix.com> writes:
>
>: >   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
>: > even if the object has no data members (or implicit vptrs).  I propose
>: > the abolition of this rule.
>
>: Note that this only applies to complete objects, not base subobjects.  So
>: your example is not relevant.
>
>   Doesn't a base subobject always have the same layout as an object
>in isolation?

 What is the meaning of your question for an abstract type?
>
>: The rule for complete objects is so that all objects have distinct
>: addresses.
>: Jason
>
>   Yes but of what real utility is it to be able to allocate empty
>objects?

 To create unique instances of things with no
properties other than their existence is very useful.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: mat@mole-end.matawan.nj.us
Date: Wed, 8 Mar 1995 07:18:04 GMT
Raw View
In article <3jfik9$m6b@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:
>
> Empty Structures Should Really be Empty.
>
> Timothy S. Murphy   5 March 1995.
>
>
>   A few observations and proposals regarding the C++ language standard.
> The last draft specification (DS) I looked at was dated 20 September 1994;
> I also refer to the ARM.
>
>    Please rip this apart, both with your editor and your words; I am
> very interested in feedback, particularly from members of the standards
> committee.
>
>
>   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
> even if the object has no data members (or implicit vptrs).  I propose
> the abolition of this rule.
>
>    The ARM, in one of its rare moments of utter stupidity, offers the
> following in support of this rule [ARM 9, introduction]: "Empty classes
> can be used as place holders during program development.  In particular,
> an empty class is sometimes used as a base class where the programmer
> suspects that two classes have something in common but hasn't yet
> determined exactly what."  Heh, heh.  1) Is it so onerous to put
> an "int" (or a virtual destructor) into an object if one really wishes
> it to be nonempty?  2) Should we warp the language so unnecessarily in the
> support of ill-conceived programs that by definition will be thrown away?
> A base class without a single method?  Come on ...
>
>    Empty base classes provide an obvious means of namespace management
> that is useful at least until real namespace implementations become
> available, and maybe even after that.
>
>    Let's abolish this silly, unnatural rule.


Namespaces will be here `Real Soon Now,' and empty base classes aren't
really a suitable way of dealing with the problem.

In any case, the rule is neither silly nor unnatural; it is quite organic,
coming from the basic requirement that every object, empty or not, have
a unique address.  That means that there must be at least one memory
location dedicated to every object, and in practice it means that any
user-defined type must have a tiling size as large as the largest unit of
`ordinary' alignment requirement.

> -- Timothy S. Murphy: A serious user and admirer of C++.
>    tmurphy@panix.com

Sigh.

You may be an admirer, but you've sure posted a lot of small nits--and
they have all been seen and disscussed before.
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: joshua@oncomdis.on.ca (joshua)
Date: 7 Mar 1995 21:20:19 GMT
Raw View
Timothy Murphy (tmurphy@panix.com) wrote:

: Empty Structures Should Really be Empty.

: Timothy S. Murphy   5 March 1995.


:   A few observations and proposals regarding the C++ language standard.
: The last draft specification (DS) I looked at was dated 20 September 1994;
: I also refer to the ARM.

:    Please rip this apart, both with your editor and your words; I am
: very interested in feedback, particularly from members of the standards
: committee.


:   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
: even if the object has no data members (or implicit vptrs).  I propose
: the abolition of this rule.

:    The ARM, in one of its rare moments of utter stupidity, offers the
: following in support of this rule [ARM 9, introduction]: "Empty classes
: can be used as place holders during program development.  In particular,
: an empty class is sometimes used as a base class where the programmer
: suspects that two classes have something in common but hasn't yet
: determined exactly what."  Heh, heh.  1) Is it so onerous to put
: an "int" (or a virtual destructor) into an object if one really wishes
: it to be nonempty?  2) Should we warp the language so unnecessarily in the
: support of ill-conceived programs that by definition will be thrown away?
: A base class without a single method?  Come on ...

:    Empty base classes provide an obvious means of namespace management
: that is useful at least until real namespace implementations become
: available, and maybe even after that.

:    Let's abolish this silly, unnatural rule.


: -- Timothy S. Murphy: A serious user and admirer of C++.
:    tmurphy@panix.com

What would be the values of the 'this pointers' of the empty objects?

If they don't hold any memory, then should this==NULL?  Does this have
any bearing on your argument?

-- Joshua




Author: tmurphy@panix.com (Timothy Murphy)
Date: 8 Mar 1995 13:52:37 -0500
Raw View
mat@mole-end.matawan.nj.us wrote:
: In article <3jfik9$m6b@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:
: >
: > Empty Structures Should Really be Empty.

: Namespaces will be here `Real Soon Now,' and empty base classes aren't
: really a suitable way of dealing with the problem.

   I don't know, they work OK for me.

: In any case, the rule is neither silly nor unnatural; it is quite organic,
: coming from the basic requirement that every object, empty or not, have
: a unique address.  That means that there must be at least one memory
: location dedicated to every object, and in practice it means that any
: user-defined type must have a tiling size as large as the largest unit of
: `ordinary' alignment requirement.

   Why is everyone so concerned with placing empty objects?  Writing
down an empty object is by definition useless.  Inheriting from one
is not.

: You may be an admirer, but you've sure posted a lot of small nits--and

   Maybe now is the time for nit-picking. :-)

: they have all been seen and disscussed before.

   Maybe there's a reason for that.  People have understandably argued
against artificial, special case rules such as empty structs, name
hiding, and the prohibition of non-constant references to temporaries.
I have yet to see a "lead-pipe" argument in support of any of these
monstrosities and find their presence difficult to comprehend,
justify, or digest.

---tim




Author: tob@world.std.com (Tom O Breton)
Date: Mon, 6 Mar 1995 22:10:05 GMT
Raw View
tmurphy@panix.com (Timothy Murphy) writes:
> Empty Structures Should Really be Empty.
        [...]
>   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
> even if the object has no data members (or implicit vptrs).  I propose
> the abolition of this rule.

I agree completely and have argued so in the past. The only thing I
would add is that the:

        ( sizeof(X)/sizeof(x[0]) )

trick (which was always kluugey) fails and needs some sort of language
construct to count an array. Which there should have been in the first
place.

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: jason@cygnus.com (Jason Merrill)
Date: 07 Mar 1995 00:11:48 GMT
Raw View
>>>>> Timothy Murphy <tmurphy@panix.com> writes:

>   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
> even if the object has no data members (or implicit vptrs).  I propose
> the abolition of this rule.

Note that this only applies to complete objects, not base subobjects.  So
your example is not relevant.

The rule for complete objects is so that all objects have distinct
addresses.

Jason




Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Tue, 7 Mar 1995 15:40:29 GMT
Raw View
In article <3jfik9$m6b@panix3.panix.com>,
Timothy Murphy <tmurphy@panix.com> wrote:
>
>Empty Structures Should Really be Empty.

 I think this is an open issue. The question is NOT whether
a class can have non-zero size, but whether pointers to
whole objects and/or member subobjects and/or base subobjects
can uniquely identify the object/member subobject/base subobject.

 If each member and base has non-zero size, then
there is a very very very important guarrantee of a 1-1 relationship
between objects/subobjects and pointer addresses.

 This identity property is absolutley fundamental
to object oriented programming.

 If objects/subobject can have zero size, the
most basic object identity property is lost.

 However, cases where it matters are rare, whereas the
savings of optimisations may not be. The question really
is whether the rigid identity guarrantee is worth it.

 Consider:

 struct X{};
 struct Y : X {
  X x1;
  X x2;
 } y;
 X *px0  = &y;
 X *px1 = &y.x1;
 X *px2 = &y.x2;

Here, if zero length (sub)objects are allowed, then all three
pointers could be equal, yet denote distinct (sub)objects.

Possibly this is OK, but the _complete_ object must have a
unique address.

Possibly, zero size is OK _provided_ all pointers have
distinct addresses -- padding can be introduced above.

Of course sizeof(X) cannot be zero or an array of X would
not be addressable... although it is hard to see how that
could matter (since all X values would be equal anyhow :-)

Anyhow ... there is a reason for the rule, and I think the
issue is not completely closed.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: tmurphy@panix.com (Timothy Murphy)
Date: 7 Mar 1995 11:56:05 -0500
Raw View
Jason Merrill (jason@cygnus.com) wrote:
: >>>>> Timothy Murphy <tmurphy@panix.com> writes:

: >   [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
: > even if the object has no data members (or implicit vptrs).  I propose
: > the abolition of this rule.

: Note that this only applies to complete objects, not base subobjects.  So
: your example is not relevant.

   Doesn't a base subobject always have the same layout as an object
in isolation?

: The rule for complete objects is so that all objects have distinct
: addresses.
: Jason

   Yes but of what real utility is it to be able to allocate empty
objects?  It seems to me that C++ has been warped in the interest of
a useless feature.

---tim





Author: tmurphy@panix.com (Timothy Murphy)
Date: 6 Mar 1995 13:00:41 -0500
Raw View
Empty Structures Should Really be Empty.

Timothy S. Murphy   5 March 1995.


  A few observations and proposals regarding the C++ language standard.
The last draft specification (DS) I looked at was dated 20 September 1994;
I also refer to the ARM.

   Please rip this apart, both with your editor and your words; I am
very interested in feedback, particularly from members of the standards
committee.


  [DS 5.3.3] stipulates that the size of _any_ class object is nonzero,
even if the object has no data members (or implicit vptrs).  I propose
the abolition of this rule.

   The ARM, in one of its rare moments of utter stupidity, offers the
following in support of this rule [ARM 9, introduction]: "Empty classes
can be used as place holders during program development.  In particular,
an empty class is sometimes used as a base class where the programmer
suspects that two classes have something in common but hasn't yet
determined exactly what."  Heh, heh.  1) Is it so onerous to put
an "int" (or a virtual destructor) into an object if one really wishes
it to be nonempty?  2) Should we warp the language so unnecessarily in the
support of ill-conceived programs that by definition will be thrown away?
A base class without a single method?  Come on ...

   Empty base classes provide an obvious means of namespace management
that is useful at least until real namespace implementations become
available, and maybe even after that.

   Let's abolish this silly, unnatural rule.


-- Timothy S. Murphy: A serious user and admirer of C++.
   tmurphy@panix.com