Topic: Why don't constructors and destructors have return types?
Author: Allan_W@my-dejanews.com (Allan W)
Date: 14 Jul 2002 01:51:10 GMT Raw View
Gennaro Prota <gennaro_prota@yahoo.com> wrote
> b) Changing 5.3.3p1 to explicitly state that sizeof considers
> exclusively "complete objects"
>
> "The sizeof operator yields the number of bytes in the object
> representation of [its operand -> *a complete object* whose type is
> determined by its operand]."
This might be feasible for objects that already have type_info.
But it's a fundamental change, and shouldn't be taken lightly.
class base { char x[4]; };
void foo(base *b) {
std::cout << sizeof(base) << "-" << sizeof(*b);
}
class der : public base { char y[2]; };
int main() {
Base b; foo(&b); std::cout << ", ";
Der d; foo(&d); std::cout << std::endl;
}
What does this print? Under current rules, it prints "4-4, 4-4" unless
alignment concerns make base bigger than 4 bytes. Under new rules
it could be "4-4, 4-6" or "4-4, 4-8". Furthermore, sizeof() can no
longer be performed at runtime except in constrained situation, such as
sizeof(base)
in the code above.
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: Sun, 14 Jul 2002 17:22:51 GMT Raw View
On 14 Jul 2002 01:51:10 GMT, Allan_W@my-dejanews.com (Allan W) wrote:
>
>Gennaro Prota <gennaro_prota@yahoo.com> wrote
> > b) Changing 5.3.3p1 to explicitly state that sizeof considers
> > exclusively "complete objects"
> >
First of all I want to clarify that
a) this (not submitted) DR is based on the assumption that the type of
base sub-objects is the type of the corresponding base class.
For instance in
class D : public B { };
I assume the D has a sub-object of type B. As the discussions on
comp.lang.c++.moderated have pointed out it's unlikely that this is
the correct way of looking at it.
What I'd like to know, and is one of the reasons why I switched to
comp.std.c++, is whether these sorts of issues were examined by the
committee and therefore taken into account when deciding the wording
of fundamental parts of the standard.
b) My descriptions of the DR are a little misleading. If you look at
the proposed resolution only, you will see that I say that sizeof(T)
gives the size of a complete object of type T. I do not say that
objects that are not complete (like data members) cannot have the same
size.
> > "The sizeof operator yields the number of bytes in the object
> > representation of [its operand -> *a complete object* whose type is
> > determined by its operand]."
>
>This might be feasible for objects that already have type_info.
>But it's a fundamental change, and shouldn't be taken lightly.
>
> class base { char x[4]; };
> void foo(base *b) {
> std::cout << sizeof(base) << "-" << sizeof(*b);
> }
>
> class der : public base { char y[2]; };
> int main() {
> Base b; foo(&b); std::cout << ", ";
> Der d; foo(&d); std::cout << std::endl;
> }
>
>What does this print? Under current rules, it prints "4-4, 4-4" unless
>alignment concerns make base bigger than 4 bytes. Under new rules
>it could be "4-4, 4-6" or "4-4, 4-8". Furthermore, sizeof() can no
>longer be performed at runtime except in constrained situation, such as
> sizeof(base)
>in the code above.
My intent was the change to 5.3.3/1 to be editorial in the sense that
it only affected the wording. No well-defined program should be
affected by the change because it doesn't concern the type you go
considering: in your example sizeof (*b) would be the size of a
complete object (as it is now) and the type of that object would still
be the -static- type of the expression *base.
***
Anyhow, please, don't formalize on the DR in se (what if base is
abstract? :-)). Consider it a rough sketch. Let's think instead if we
can consider the base sub-object of der to be of type base or not.
That's the real question.
***
Genny.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: 12 Jul 2002 02:58:39 GMT Raw View
{ To mods: Sorry for cross-posting. But I think it is now necessary to
switch to comp.std.c++. Follow-ups go there. }
On 11 Jul 2002 02:02:06 -0400, jpotter@falcon.lhup.edu (John Potter)
wrote:
>On 10 Jul 2002 09:26:52 -0400, Gennaro Prota <gennaro_prota@yahoo.com>
>wrote:
>
>>
>> { Note to mods: I posted this on July 6 but it never appeared.
>> Originally it was cross-posted to comp.std.c++, where I think it would
>> be more appropriate. (Maybe you can forward a copy? :-))
>>
>> Tracking number was 35735 or 35739. }
>>
>>
>>
>> On 5 Jul 2002 22:53:04 -0400, jpotter@falcon.lhup.edu (John Potter)
>> wrote:
>>
>> >On 5 Jul 2002 12:02:14 -0400, Gennaro Prota <gennaro_prota@yahoo.com>
>> >wrote:
>> >
>> >> On 5 Jul 2002 06:34:45 -0400, jpotter@falcon.lhup.edu (John Potter)
>> >> wrote:
>> >
>> >> >Yes, the sizof operator operates on types which have object
>> >> >representations. Expressions also have type as an attribute.
>> >
>> >> Types don't have object representations. Objects have. I don't know
>> >> why you are upsetting all the standard terminology :-) (BTW you
>> >> cannot think the size of an object to depend on its type only, because
>> >> base sub-objects and complete objects of the same type may have
>> >> different sizes)
>> >
>> >3.9/4. Note that object representation applies only to objects of
>> >type. A base subobject has neither a name nor a name for its type
>> >(which is base subobject of D). There is no way to apply sizeof to it
>> >and it does not have an object representation.
>
>> What is D? And what are "objects of type"???
>
>If B is a base of D then the type of that subobject is B base of D and
>it might not have the object representation of a B object.
My point is that it might not have the same object representation of a
*complete object* of type B. Here's the sketch of the DR I prepared in
response to the already mentioned
http://groups.google.com/groups?selm=3CC155C6.C5EB5BFA%40wizard.net
I have not submitted it (yet) because of another problem that I don't
want to arise here (this stuff is already complicated enough, uh?
:-)). Note that I'm not saying the defect report is right and that
mine is THE answer to all these questions. Only that this is (so far)
my way of rationalizing part of the issue:
----------------------------- sketch ---------------------
Paragraph 3.9p4 (see the quote below) of the C++ standard (ISO/IEC
14882) seems to miss the case of "empty base sub-objects" when
speaking of object sizes. Here's the current wording:
"The object representation of an object of type T is the sequence of N
unsigned char objects taken up by the object of type T, where N equals
sizeof(T)."
Now, consider the following example:
class A {};
class B : public A { public: int i;};
A a;
B b;
Here, the A subobject in b may occupy 0 bytes, whereas the complete
object a cannot (1.8p5). What is the object representation of that
subobject, according to 3.9p4?
PROPOSED RESOLUTION:
/
a) replacing ",where N equals sizeof(T)" in 3.9p4 with "where N is a
non-negative integer constant. For base class sub-objects N may be 0
(i.e. the object representation of a base class sub-object may be an
empty sequence). In all other cases N shall be (>0 and be equal to)
sizeof(T)."
Note that this proposed wording leaves undefined whether base
sub-objects of type T may have any possible size in the range ] 0,
sizeof(T) [, or even in the range ] sizeof(T), +inf [
b) Changing 5.3.3p1 to explicitly state that sizeof considers
exclusively "complete objects"
"The sizeof operator yields the number of bytes in the object
representation of [its operand -> *a complete object* whose type is
determined by its operand]."
c) Changing 5.3.3p2: When applied to a class, the result is the number
of bytes in [an object-> in a complete object] of that class including
any padding required....
/
-------------------------- end sketch ---------------------
Note that my idea is that sizeof only consider complete objects.
Non-complete objects do have an object representation, but you can't
use sizeof to know of how many bytes it consists. It's obvious: what
do you use as sizeof argument?
As to the virtual base problem, see below.
>
>> In any case, you are right that the base sub-object doesn't have a
>> name but are terribly wrong if you think that it's type is different
>> from the type of the base class and/or you think it doesn't have an
>> object representation (apart from other problems the standard may have
>> about that)
>
>3.9/4 The object representation of an object of type T ...
>
>There is nothing that you can substitute for T in that statement for a
>B base subobject of D. If you claim that it is of type B then it must
>have an object representation which is sizeof(B) contiguous bytes.
The last sentence is not necessarily true if we make it explicit that
sizeof only refers to complete objects. Also I don't think you have to
push that "substitute something for T" too far; T is presumably only a
placeholder to write sizeof(T) later in the same sentence.
Otherwise there would also be the following implication:
struct { int i; int j; } instance;
The type of instance has not a name. Does this mean that 3.9/4 doesn't
apply?
Anyhow, to discuss what really is the type of a sub-object and all its
implications you should say me what is a "type" according to the
standard.
Then, please, answer to this:
a) struct B { int n };
struct B1 : public { int n1; }
struct B2 : public { int n2; }
struct C : public virtual B1, public virtual B2 { };
struct Plain1 : public B { char c; }
struct Plain2 : public B {};
struct Virtual : public B1, public B2 { }
The B subobject in Plain1 has a type different from the B subobject in
Virtual?
b) Suppose that the compiler decides to apply the EBO to Plain1 and
not to Plain2: does the two base subobjects have different types?
And can the compiler apply the EBO to some instances and not to
others?
c) the type of the B sub-object (please, let me call it that way)
should be (1.8) "the type with which it is created". For classes, I
always interpreted that sentence as "the class type of the
constructor". How do you interpret it now?
> We
>could not have empty base subobjects nor discontiguous base objects
>which happens in classes with virtual base classes. A base subobject
>is not an "object of type".
>
Finally I have taken a look at the thread "C++ objects [again]". I
missed it because I was not enough interested in the original
question.
Well, tell me what does discontiguous mean (Please, don't think I'm
quibbling: I really believe that this kind of discussion do NEED
robust definitions).
For example (James Kanze's code):
struct VB { char vbi ; } ;
struct B : virtual VB { char bi ; } ;
struct C : virtual VB { char ci ; } ;
struct D : B, C { int di ; } ;
int main() {
D d ;
std::cout << "sizeof B = " << sizeof( B ) << '\n' ;
std::cout << "distance between bi and vbi = "
<< &d.vbi - &d.bi << '\n' ;
return 0 ;
}
This code accesses two sub-objects of D. None of them is the VB
subobject. You cannot name that subobject. So how does this
demonstrate that it is discontiguous?
>Do you have a better rationalization?
>
>> 1. Base class sub-objects have type (10/2)
>
>It says that the derived class will have a sub-object of class base,
>it does not say that the type of that sub-object is base. Word games.
And what does "a sub-object of class base" mean??
>
>> 2. Sub-objects are objects (1.8/2)
>
>Agreed, but you can't spell their types.
Not always (think of arrays). Anyhow is the problem the spelling?
>
>> Suppose that constructors are not functions
>
>Let's see if we can end this nonsense. I started with a statement
>that it is debatable and that it is a semantics game.
>
>free function
>static member function
>non-static member function
>copy assignment operator
>destructor
>default constructor
>copy constructor
>other constructor
>
>I choose to call the first four functions and the others function-like
>because they do not have certain properties of functions. You choose
>to call them all functions with possible subcategories of normal and
>wierd. I see no point in trying to justify either. They are both
>useful for understanding certain things.
You snipped exactly the numerous reasons I gave to say that the last
four are also considered functions in the standard. I explained that
your approach would be asking for trouble and that it would have
required to remember of those particular "exceptions" when speaking of
functions, of function body, of function definition, of parameters of
a function and a lot of other things, without giving any reasonable
advantage. I quoted a lot of paragraphs in the previous post and they
concern fundamental pieces of the standard like "lifetime of
temporaries" and the One Definition Rule. I even mentioned DR201. Did
you read it?
I don't understand why it should be "useful" to consider them
non-functions. To understand certain things. What things?
>
>> >> > > Why? Can't mt_ptr -> ~mytype be the postfix expression that is
>> >> > > followed by ( expression-listopt ) ?
>
>> >> >It is, and when followed by () it is (member) function call. What it
>> >> >can't be is anything involving pseudo-destructor-name because that is
>> >> >a term only defined for scalar types.
>
>> >> Gulp! Tell me where is it written...
>
>> >5.1/7 ~class-name is an id-expression.
>
>> Wrong wrong wrong! :-(((
>
>> ~class-name can't be a qualified-id! (It's none of the possible
>> unqualified-ids in 5.1)
>
>> >5.2.4/1 pseudo-destructor-name designates a non-class type.
>
>> 5.2.4/1 is a little ambiguous.
>
>I don't think so.
>
>pseudo: apparently, not actually, sham, pretending
>pseudo-destructor: not actually a destructor
>pseudo-destructor-name: syntactic element which names nothing
>pseudo-destructor-call: expression which calls nothing
I'm saying the same for a long time now :-) Where we don't agree is
that you think that the presence of a pseudo-name makes the entire
function-call-expression a pseudo-call. Instead I say that
syntactically we only have function calls and semantically we have
function calls or pseudo_function_calls depending on whether in ~T the
T names a class type or not.
I gave an example too. It's a bit frustrating to get the impression
that you didn't read what I wrote :-(
>
>struct S { };
>int main () {
> int i;
> i.~int();
> // postfix-expression ()
> // postfix-expression -> postfix-expression .
> // pseudo-destructor-name
> // pseudo-destructor-name -> ~ type-name
> S s;
> s.~S();
> // postfix-expression ()
> // postfix-expression -> postfix-expression . id-expression
> // id-expression -> unqualified-id
> // unqualidied-id -> ~ class-name
> // You may need to zoom to see that ~ in the standard
> }
The key is that there's nothing like pseudo-destructor-call in the
grammar (the name with the dashes is mine), but there's something like
a pseudo-destructor-name.
The expressions:
i.~integer()
s.~S()
[in the first one I'm assuming a typedef int integer; your code is
illegal] qualify both as postfix-expression(), and both according to
5.2.2 are function calls (function call expressions). Both contains a
pseudo-destructor-name.
postfix-expression:
postfix-expression ( expression-listopt )
postfix-expression . pseudo-destructor-name
The distinction between "true calls" and "pseudo-calls" is semantical,
i.e. we call "pseudo function calls" those function calls that refer
to non-class types.
Otherwise tell me how do you explain 12.4/12.
Genny.
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Fri, 12 Jul 2002 16:14:14 GMT Raw View
There are three only slightly related topics in the article. I have
split replies with appropriate subjects. I will be off line for a
month and will check to see anyone else has anything to say then.
On 12 Jul 2002 02:58:39 GMT, Gennaro Prota <gennaro_prota@yahoo.com>
wrote:
> >> Suppose that constructors are not functions
> >Let's see if we can end this nonsense. I started with a statement
> >that it is debatable and that it is a semantics game.
> >free function
> >static member function
> >non-static member function
> >copy assignment operator
> >destructor
> >default constructor
> >copy constructor
> >other constructor
> >I choose to call the first four functions and the others function-like
> >because they do not have certain properties of functions. You choose
> >to call them all functions with possible subcategories of normal and
> >wierd. I see no point in trying to justify either. They are both
> >useful for understanding certain things.
> I don't understand why it should be "useful" to consider them
> non-functions. To understand certain things. What things?
Q. Subject of article.
A. Because they are not functions.
Q. Why are they not functions.
A. Because they do not have return types.
There are no loose ends in that circle. ;-)
If you want a formal ruling, maybe someone else will provide one.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]