Topic: Constructing an array of class-type elements.
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Tue, 24 Aug 1993 10:24:57 GMT Raw View
In article <4791@hpwala.wal.hp.com> pabloh@hpwala.wal.hp.com (Pablo Halpern ) writes:
>In article <rfgCBv3A5.K4x@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>|> In article <CBu9wD.Lzo@noose.ecn.purdue.edu> luj@ecn.purdue.edu writes:
>|> >In article <rfgCBtI4B.GEK@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
>|> >
>|> >|> [ deleted ...]
>|> >|> >>
>|> >|> >> typedef S T[3];
>|> >|> >>
>|> >|> >> S *sp;
>|> >|> >>
>|> >|> >> int
>|> >|> >> test ()
>|> >|> >> {
>|> >|> >> sp = T();
>|> >|> >
...
>|> >|> ... I know of no rule which would render it INVALID semantically.
>
>Well, actually, what is happening semantically is that T() would create a
>temporary variable of type T, a.k.a. array of three S. Thus, the behavior
>of this code is unspecified, since the lifetime of the temporary is not
>guarenteed.
Wrong. The important part of the behavior (i.e. that part which affects
the outcome) is (or rather should be) well specified. The timing of the
destruction of the temporary is of no importance to the issue here.
>Your code takes the address of a temporary, which is bad news
It may be bad news, but it is perfectly valid.
>By the time you test for the number of
>times the constructor was called, the temporary's destructors could have
>been called.
Yea. So?
>The code should still have worked, however, since you never
>use the *value* of these temps.
Exactly. The above code *should* work, and since it would be a violation
of a general rule of the language if objects of a class type which has
constructors were allowed to be created *without* being properly constructed,
I must assume that the statement:
sp = T();
must in fact cause three constructor calls to occur.
Now for the fun part...
Most compilers choke *at compile-time* on the above code! They can't even
get us to run-time! And the remainder? Well, you can bet your bottom
dollar that they all generate code which does the Wrong Thing at run-time.
(Isn't C++ wonderful? This may be the only popular language where you can
still find valid constructs which NO available compiler properly groks.)
--
-- Ronald F. Guilmette ------------------------------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
Author: pabloh@hpwala.wal.hp.com (Pablo Halpern )
Date: Fri, 20 Aug 1993 15:30:07 GMT Raw View
In article <rfgCBv3A5.K4x@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
|> In article <CBu9wD.Lzo@noose.ecn.purdue.edu> luj@ecn.purdue.edu writes:
|> >In article <rfgCBtI4B.GEK@netcom.com>, rfg@netcom.com (Ronald F. Guilmette) writes:
|> >
|> >|> [ deleted ...]
|> >|> >>
|> >|> >> typedef S T[3];
|> >|> >>
|> >|> >> S *sp;
|> >|> >>
|> >|> >> int
|> >|> >> test ()
|> >|> >> {
|> >|> >> sp = T();
|> >|> >
|> >|> >I do not understand this line -> sp = T(); and neither does Sun`s CC
|> ...
|> >|> ... I know of no rule which would render it INVALID semantically.
|> ...
|> >Semantically it is _undefined_ if you don't want to
|> >call it invalid. See below.
|> ...
|> >ARM (8.2.4, p136):
|> > "When an identifier of array type appears in an expression,
|> > except as the operand of sizeof or & or used to initialize
|> > a reference(8.4.3), it is converted into a pointer to
|> > the first memeber of the array."
|> >
|> >Therefore, in the expression of "T()" in your test program, T is a _pointer_
|> >to S. i.e. T is a _simple_ type. Hence the result is _undefined_
|> >according to your quote fo ARM 5.3.2.
|>
|> Your analysis, although incorrect, serves to illustrate a couple of serious
|> problems in the section of the ARM which you have quoted.
|>
|> In the first place, it is quite completely apparent (to students of the
|> ANSI C standard at least) that Stroustrup goofed when he wrote the ARM
|> rule which you have quoted. I'm quite sure that he did not mean to say
|> "an identifier of array type". Rather, what was intended was something
|> more like:
|>
|> "Each EXPRESSION or SUBEXPRESSION which (initially) has some array
|> type (e.g. T[N] or T[]) and which appears in some context OTHER
|> THAN as the operand of the `sizeof' or unary `&' operator (or as
|> the initializer expression for an object declared to have some
|> reference type) is implicitly converted to to a value of type T*.
|> The resulting T* value (after this conversion) is a pointer to
|> the first element of the original array object, and is not an
|> lvalue."
|>
I agree with your rephrasing of the standard. First, it is arguable wether
an identifier representing an array type is the same as an "identifier of
array type." Second, it would seem that any expression of type "array of
T" should degenerate to "pointer to T", not just simple identifiers. Your
version is much clearer and broader.
|> >|> ... I know of no rule which would render it INVALID semantically.
Well, actually, what is happening semantically is that T() would create a
temporary variable of type T, a.k.a. array of three S. Thus, the behavior
of this code is unspecified, since the lifetime of the temporary is not
guarenteed. Your code takes the address of a temporary, which is bad news
(and may eventually be illegal). By the time you test for the number of
times the constructor was called, the temporary's destructors could have
been called. The code should still have worked, however, since you never
use the *value* of these temps.
|>
|> -- Ronald F. Guilmette ------------------------------------------------------
--
- Pablo
-------------------------------------------------------------------------
Pablo Halpern Permanent: (508) 435-5274 phalpern@world.std.com
Thru 3/94: (508) 659-4639 pabloh@wal.hp.com
-------------------------------------------------------------------------
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 15 Aug 1993 21:19:26 GMT Raw View
In article <Aug10.223427.34802@halcon.dpi.udec.cl> llongeri@miro.die.udec.cl (Luis LONGERI H.) writes:
>Ronald F. Guilmette (rfg@netcom.com) wrote:
>: I have tried several C++ compilers, and none of them seem to do what I
>: think (intutively) is the Right Thing with the following small test
>: program.
>
>: As far as I know, C++ compilers should compile this code without complaint,
>: and the resulting executable, when executed, should exit quietly with a
>: zero exit status.
>
>: #include <stdio.h>
>:
>: int err_count = 0;
>: int ctor_count = 0;
>:
>: struct S
>: {
>: S () { ctor_count++; }
>: };
>:
>: typedef S T[3];
>:
>: S *sp;
>:
>: int
>: test ()
>: {
>: sp = T();
>: if (ctor_count != 3)
>: {
>: printf ("wrong # of elements constructed: %d\n", ctor_count);
>: err_count++;
>: }
>:
>: return err_count;
>: }
>:
>: int main () { return test (); }
>: --
>
>Well, I tried your code, actually, it didn't compile. I suppose that by writing
> sp = T();
>you wanted to create an array off 3 structures. Well this line didn't compile
>and to me, it didn't make sense.
It makes complete sense. RTFARM.
>( I use Apollo's Domain C++ compiler )
Yes. Thank you. I believe we can now say with some certainty that essentially
all cfront-based implementations have this same bug.
--
-- Ronald F. Guilmette ------------------------------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
Author: llongeri@miro.die.udec.cl (Luis LONGERI H.)
Date: Tue, 10 Aug 93 22:34:27 GMT Raw View
Ronald F. Guilmette (rfg@netcom.com) wrote:
: I have tried several C++ compilers, and none of them seem to do what I
: think (intutively) is the Right Thing with the following small test
: program.
: As far as I know, C++ compilers should compile this code without complaint,
: and the resulting executable, when executed, should exit quietly with a
: zero exit status.
: #include <stdio.h>
:
: int err_count = 0;
: int ctor_count = 0;
:
: struct S
: {
: S () { ctor_count++; }
: };
:
: typedef S T[3];
:
: S *sp;
:
: int
: test ()
: {
: sp = T();
: if (ctor_count != 3)
: {
: printf ("wrong # of elements constructed: %d\n", ctor_count);
: err_count++;
: }
:
: return err_count;
: }
:
: int main () { return test (); }
: --
Well, I tried your code, actually, it didn't compile. I suppose that by writing
sp = T();
you wanted to create an array off 3 structures. Well this line didn't compile
and to me, it didn't make sense. So I changed it with:
sp = new T();
and now it did compile. And it worked fine when I executed it.
( I use Apollo's Domain C++ compiler )
Luis Longeri H
llongeri@renoir.die.udec.cl
Author: hendrik@vedge.com (Hendrik Boom)
Date: Fri, 13 Aug 1993 18:13:04 GMT Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
: I have tried several C++ compilers, and none of them seem to do what I
: think (intutively) is the Right Thing with the following small test
: program.
:
: As far as I know, C++ compilers should compile this code without complaint,
: and the resulting executable, when executed, should exit quietly with a
: zero exit status.
:
: Has anyone got a C++ compiler which does the Right Thing with this example?
:
: -- rfg
:
:
: ============================================================================
: /* (C) 1993 Ronald F. Guilmette; all rights reserved. */
:
: /* Section 5.2.3; C++ ARM:
:
: "A simple-type-name (7.1.6) followed by an (empty) pair of paren-
: theses constructs a value of the specified type. If the type is
: a class with a suitably declared constructor that constructor will
: be called; otherwise the result is an undefined value of the speci-
: fied type."
:
: Check that an array type value whose element type is a class type (with
: an explicit default constructor) may be constructed using this notation.
: */
:
: #include <stdio.h>
:
: int err_count = 0;
: int ctor_count = 0;
:
: struct S
: {
: S () { ctor_count++; }
: };
:
: typedef S T[3];
:
: S *sp;
:
: int
: test ()
: {
: sp = T();
: if (ctor_count != 3)
: {
: printf ("wrong # of elements constructed: %d\n", ctor_count);
: err_count++;
: }
:
: return err_count;
: }
:
: int main () { return test (); }
: --
:
: -- Ronald F. Guilmette ------------------------------------------------------
: ------ domain address: rfg@netcom.com ---------------------------------------
: ------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
I'd certainly hope that C++ compilers would behave as you describe.
BUT, the quoted text appears to imply that they should not.
T is not a class, with or without a constructor, and so T() should
yield an undefined value.
Ughh.
hendrik.
--
-------------------------------------------------------
Try one or more of the following addresses to reply.
at work: hendrik@vedge.com, iros1!vedge!hendrik
at home: uunet!ozrout!topoi!hendrik
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Thu, 5 Aug 1993 18:34:35 GMT Raw View
I have tried several C++ compilers, and none of them seem to do what I
think (intutively) is the Right Thing with the following small test
program.
As far as I know, C++ compilers should compile this code without complaint,
and the resulting executable, when executed, should exit quietly with a
zero exit status.
Has anyone got a C++ compiler which does the Right Thing with this example?
-- rfg
============================================================================
/* (C) 1993 Ronald F. Guilmette; all rights reserved. */
/* Section 5.2.3; C++ ARM:
"A simple-type-name (7.1.6) followed by an (empty) pair of paren-
theses constructs a value of the specified type. If the type is
a class with a suitably declared constructor that constructor will
be called; otherwise the result is an undefined value of the speci-
fied type."
Check that an array type value whose element type is a class type (with
an explicit default constructor) may be constructed using this notation.
*/
#include <stdio.h>
int err_count = 0;
int ctor_count = 0;
struct S
{
S () { ctor_count++; }
};
typedef S T[3];
S *sp;
int
test ()
{
sp = T();
if (ctor_count != 3)
{
printf ("wrong # of elements constructed: %d\n", ctor_count);
err_count++;
}
return err_count;
}
int main () { return test (); }
--
-- Ronald F. Guilmette ------------------------------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------