Article View: comp.std.c++
Article #1864Re: What is sizeof(T&) ??
From: J. Kanze
Date: Tue, 29 Aug 1995 15:11
Date: Tue, 29 Aug 1995 15:11
203 lines
9586 bytes
9586 bytes
Tom Payne (thp@cs.ucr.edu) wrote:
|> This posting follows up a posting in comp.lang.c++ dealing with the portion
|> of the draft standard that deals with sizeof applied to types.
|> In article <41nfb7$qau@druid.borland.com> Pete Becker (pete@borland.com) wrote:
|> :
|> : In article <41lqnl$fgb@galaxy.ucr.edu>, thp@cs.ucr.edu says...
|> : >
|> : >As I read 5.3.3, it seems to support my claim:
|> : >
|> : > 1 The sizeof operator yields the number of bytes in the object represen-
|> : > tation of its operand. The operand is either an expression, which is
|> : > not evaluated, or a parenthesized type-id. The sizeof operator shall
|> : > not be applied to an expression that has function or incomplete type,
|> : > or to an enumeration type before all its enumerators have been
|> : > declared, or to the parenthesized name of such types, or to an lvalue
|> : > that designates a bit-field. [Note: sizeof(char) is 1, but
|> : > sizeof(bool) and sizeof(wchar_t) are implementation-defined. 10) See
|> : > _intro.memory_ for the definition of byte and _basic.types_ for the
|> : > definition of object representation. ]
|> : >
|> : > 2 When applied to a reference, the result is the size of the referenced
|> : > object. ...
|> : >
|> : >It seems to me that (2) above is somewhat redundant in that this is
|> : >the way references work under all operations, as stated elsewhere.
|> : >
|> : >But, in the expression sizeof(Widget&), I am applying sizeof, not to a
|> : >reference, but to a parenthesized type-id for a reference type, which
|> : >should yield the number of bytes in the object representation of this
|> : >operand, (Widget&).
|> : >
|> : >This is not an inference based on internal representation but my
|> : >direct reading of a portion of the standard defines a language feature
|> : >that reports a feature (size) of those representations to the
|> : >programmer.
|> :
|> : Widget& w = something;
|> :
|> : Are you seriously arguing that sizeof(Widget&) need not be the same as
|> : sizeof(w)? Please apply a little common sense in reading the working paper. It
|> : is, after all, a document written by humans to be read by humans. It is not,
|> : and will not be, perfect. If it is possible to interpret something in a way
|> : that is clearly absurd, and it is also pssible to interpret the same thing in
|> : a way that is consistent with the rest of the paper and actually useful, do
|> : the latter.
|> :
|> Upon reading in a C++ book that it is often more efficient to pass
|> parameters by reference (because references are often smaller than
|> their referrentss),
Most of the C++ books I've seen suggest passing parameters by reference
not because of the size, but because a reference does not require
calling the constructor.
|> an experienced C programmer decides to determine
|> at what referrent size this effect becomes true. Knowing, as all C
|> progrmmers do, that the sizeof operator "yields the number of bytes in
|> the object representation of its operand", which may be an expression
|> or the parenthesized name of a type, he immediately runs the program:
|> #include <iostream.h>
|> int main() { cout << sizeof(Widget&) << endl; }
|> The result, 17, he finds oddly coincidental; it's the same prime value
|> as sizeof(Widget).
|> "How strange!"
|> He tries some other types with the even stranger result that in all
|> cases sizeof(T&) is equal to sizeof(T).
|> "Astonishing!! So much for the book's claim that references are more
|> compact than their referrents. But I wonder why these representations
|> vary in size this way."
|> Now, let's apply some common sense. We can blame the victim,
|> insisting that he has failed to "apply a little common sense" and has
|> interpreted the C++ semantics of sizeof "in a way that is clearly
|> absurd." Or, we can design the language in a way that minimizes the
|> astonishment factor by preserving the well-known semantics of sizeof.
What are the well-known semantics of sizeof with regards to reference
types?
More importantly, what *do* you want the compiler to return for sizeof(
Widget& )? What is the size of a reference? Logically, I can see
several possibilities:
1. The size of Widget. After all, a reference itself is just another
name for the object; why should sizeof( Widget& ) give different results
than sizeof( Widget )?
2. 0. This is the minimum space needed to implement a reference. In
many cases, it is all of the space the compiler will need. In the other
cases, the additional space can be considered an implementation detail,
like padding, or the vptr. On the other hand, this really doesn't seem
to be a very useful rule.
3. The actual space used. This might work for expressions which result
in a reference type (except that no expression ever results in a
reference type), but since the actual space used varies from one use to
the next (on all of the compilers I'm familiar with), which one is the
compiler supposed to chose.
4. Make the construction illegal. In one way, I'm tempted to argue that
this is implicitly the current status quo; sizeof( X ) gives the amount
of space an X occupies in an array, and since arrays of references are
illegal...
(Concerning the last, consider the following:
struct X { int i ; char c ; } ;
X x ;
char c[ 3 ] ;
On my system, sizeof( X ) == 8, as does sizeof( x ). And of course,
sizeof( c ) == 3. Curiously, however, the two variables only take up a
total of 8 bytes; in this particular case, the physical sizeof x is 5,
and not 8. This is a perfectly legal, and frequent, implementation.)
|> There are two issues at hand:
|> * What does the present wording say is the semantics of sizeof
|> as it applies to parenthesized names of types?
I think one could argue for 1 or 4, above, but I'm pretty sure that the
intent was 1.
|> * What should be the semantics of sizeof as applied to
|> parenthesized names of types?
I'm beginning to think I prefer 4, but the issue of existing code speaks
in favor of 1.
|> IMHO, logic, common sense, and good taste in language design all point
|> to a strict interpretation of the present wording.
|> Specifically, I find nothing in the present wording that would support
|> an interpretation that sizeof(T&) == sizeof(T). Also, I find nothing
|> convincing about the argument that, because applying sizeof to a
|> reference expression, applying sizeof to a reference type must yield
|> the size of the referrent type. It's similar to the non-sequitur that
|> brains can't think because neurons can't think. There is no reason to
|> believe that properties of the components (in this case references)
|> can or must be shared by an ensemble (in this case a reference type).
Just to cloud the issues:
Consider the following structure:
struct X { Widget& w1 ; Widget& w2 ; X() ; } ;
X x ;
// We now have:
sizeof( x ) < sizeof( x.w1 ) + sizeof( x.w2 )
// Or: the total is *less* than the sum of its parts.
// C programmers, of course, expect the inverse.
Another example:
struct X { int& ri ; int i ; X() ;} ;
X x ;
assert( (void*)( &x.ri ) == (void*)( &x ) ) ;
C programmers would normally expect the assertion to hold; after all,
``common sense'' (and the C standard) says that the address of the first
element of a structure is the same as the address of the structure. (In
C++, this only holds for PODS's.)
Another interesting case:
struct X { int i1 ; int& i2 ; int i3 ; X() ; } ;
X x ;
Again, the C standard requires that structure elements occur in order,
so the C programmer would expect that:
(char*)( &x.i1 ) < (char*)( &x.i2 ) &&
(char*)( &x.i2 ) < (char*)( &x.i3 )
Again, I don't think that this will ever be true. Despite paragraph 11
section 9.2 of draft standard: ``Nonstatic data members of a class
declared without an intervening access specifier are allocated so that
later members have higher addresses within a class object.'' (The
reason: IMHO, i2 is not a ``nonstatic data member'', but simply a name
for an object. The actual object is not necessarily even a member.)
About all I can conclude from this is that C++ is not C, and trying to
assimilate elements of C++ which are not found in C to elements which
are found in C is going to cause problems.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
--Beratung in industrieller Datenverarbeitung
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID:
<41v7eh$2b1@gabi.gabi-soft.fr>Path:
arc1-ca.pugleaf.net!engnews2.Eng.Sun.COM!taumet!clamageReferences:
<199508290413.VAA02818@corvette.ucr.edu>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!engnews2.Eng.Sun.COM!taumet!clamage From: kanze@gabi-soft.fr (J. Kanze) Newsgroups: comp.std.c++ Subject: Re: What is sizeof(T&) ?? Date: 29 Aug 1995 15:11:16 GMT Organization: GABI Software, Sarl. Approved: clamage@eng.sun.com (comp.std.c++) Message-ID: <41v7eh$2b1@gabi.gabi-soft.fr> References: <199508290413.VAA02818@corvette.ucr.edu> NNTP-Posting-Host: taumet.eng.sun.com Content-Type: text X-Newsreader: TIN [version 1.2 PL2] Content-Length: 8649 X-Lines: 199 Originator: clamage@taumet