Topic: IMPRESS YOUR FRIENDS. Two questions for Real Gurus (tm)
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 18 Mar 1994 17:03:02 GMT Raw View
djones@megatest.com (Dave Jones) writes:
>From lmcropa@lmc.ericsson.se (Roxsan Payette):
>> devitto@anise (Domenico De Vitto) writes:
>>> djones@megatest.com (Dave Jones) writes:
>>> :
>>> : In the following code, what is the guaranteed lifetime of the compiler-
>>> : generated temporary object created by operator+ ?
>>> :
>>> : foo((SomeType)(obj1 + obj2));
>>>
>>> Currently compiler dependant. It should be (says the ANSI comittee) til the
>>> end of the statement (they use another word, but that's the general idea).
>>
>> The other word is "end of full expression" which is not the same thing
>> as til the end of the statement
No, in general it's not, but it is in the case of expression-statements
such as the above.
>>(although what the ANSI comittee says these
>> days is not yet part of standard and thus, unsupported by compiler vendors.
>>
>> The behavior of the statement above is undefined.
Well, when we do finally get a standard, the behaviour will be defined.
And eventually compilers will even implement the behaviour required
by the standard.
>... this seems like a pretty bad situation. To be safe,
>it seems to me that the committee should stipulate that the temp object
>(obj1 + obj2) must survive during the intire call to foo().
The committee _has_ so stipulated. I think Roxsan Payette was
just pointing out that you can't yet rely on this, because it
will be a while before compilers implement the behaviour which the
committee has decided on.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 18 Mar 1994 18:01:46 GMT Raw View
djones@megatest.com (Dave Jones) writes:
>
>How do I write a function prototype that takes an array of pointers
>to character strings as an argument, and promises not to muck with either the
>array or the strings?
There's a variety of ways - here's a couple:
void func(char const * const *);
void func(const char * const *);
>It would seem that the "safe" function below promises just that.
>Indeed the compiler trusts it with arrays that are not supposed to be
>written to. But oddly the compiler does not trust it with LESS protected
>types -- types that are "less const".
This is a weakness of the C++ type system. The committee has recognized
this weakness; I think that they recently accepted a proposal to
allow code such as yours.
>The compiler vendor's documentation says, in effect, "Trust us. We know
>what we are doing. The compiler is right to complain." (The actual text is
>included below.)
The compiler is right to complain about the case mentioned in their
documentation below, which is unsafe. Your code is a slightly different
case which turns out to be safe. But until recently the C++
type system didn't distinguish between these two cases, hence the
compiler's rejection of your code. You'll probably need to use
a cast.
>The "migration document" says,
>
> Note that passing a value of type
> char** to an argument of type const char** is illegal in both C++ and
> ANSI C. This is not an error or oversight in the standard as such
> assignments open a hole in the type system and violate const safety.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: swf@tdat.ElSegundoCA.NCR.COM (Stan Friesen)
Date: Mon, 14 Mar 94 16:38:35 PST Raw View
In article <1994Mar10.193226.23124@exu.ericsson.se>, lmcropa@lmc.ericsson.se (Roxsan Payette) writes:
|> In article <2lnaco$9cv@snlsu1.london.sinet.slb.com>, devitto@anise (Domenico De Vitto) writes:
|> > djones@megatest.com (Dave Jones) writes:
|> > :
|> > : foo((SomeType)(obj1 + obj2));
|> >
|> > Currently compiler dependant. It should be (says the ANSI comittee) til the
|> > end of the statement (they use another word, but that's the general idea).
|>
|> The other word is "end of full expression" which is not the same thing
|> as til the end of the statement ...
|>
|> The behavior of the statement above is undefined.
The way I would interpret "end of full expression" in this case makes
the call perfectly legitimate as presented. A function call is, itself,
an expression, so the largest expression containing the creation of the
temporary is the funtion call. This makes the end of the full expression
the return from the function.
--
swf@elsegundoca.ncr.com sarima@netcom.com
The peace of God be with you.
Author: djones@megatest.com (Dave Jones)
Date: Tue, 15 Mar 1994 00:57:24 GMT Raw View
Author: kanze@us-es.sel.de (James Kanze)
Date: 15 Mar 1994 13:41:49 GMT Raw View
In article <2lnaco$9cv@snlsu1.london.sinet.slb.com> devitto@anise
(Domenico De Vitto) writes:
|> djones@megatest.com (Dave Jones) writes:
|> : Question number 2:
|> : How do I write a function prototype that takes an array of pointers
|> : to character strings as an argument, and promises not to muck with either the
|> : array of the strings?
|> This is what Bjarne says: (ish)
|> const char* const fred;
|> fred[0]=0; // error
|> fred="hello"; // error
|> ie: "const char*" = pointer to constant
|> "char* const" = constant pointer
|> "const char* const" = constant pointer to a constant
|> I think this is what you're after, but I could be wrong....
You are. The following function *declarations* are equivalent:
extern void f( char const *const p ) ;
extern void f( char const * p ) ;
The last const is only significant on the function *definition*.
In both cases, the function takes a pointer to a const char, or an
array of const char's, and not a pointer to an array of pointers.
Try the following:
extern void f( char const *const array[] ) ;
or: extern void f( char const *const * array ) ;
The original poster obtained the equivalent of the first of these
using typedef's, and tried to pass it an array without any of the
const's. The compiler complained, and the vendor apparently defended
the compiler.
Strictly speaking, the vendor is correct for *C*, and, I believe, the
ARM (although I do not have my copy handy). He is *not* correct for
the upcoming ISO standard.
If I remember right, the sequence in question was the following:
char const c = '\a' ;
char const* pc = &c ;
char* q ;
char const** pq = &q ; // Unsafe
*pq = p ;
*q = '\b' ;
Note that if the operation marked unsafe were allowed (it is not), the
above program fragment would be legal C/C++, which would allow
modifying the 'const' c without a cast.
Because of this, ISO banned the above construct, using words which
effectivly banned all removal of const for more than one level of
indirection. (I don't have my copy of the C standard handy either, to
quote the exact words.) I believe that it was Andy Koenig who first
remarked that the above construct *is* safe if all of the intermediate
pointers are const, eg: if 'pq' has the type 'char const*const*', then
the assignment '*pq = p' is illegal, and the const safety has not been
impaired. The C++ standards committee has since voted a modification
which allows the above. (One of the committee members did a full
analysis, with mathematical proofs, of what was and was not safe. His
findings are reflected in the current working papers, and will no
doubt be part of the final standard.)
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: dag@control.lth.se (Dag Bruck)
Date: 15 Mar 1994 18:32:18 GMT Raw View
>>>>> On Mon, 14 Mar 94 16:38:35 PST, swf@tdat.ElSegundoCA.NCR.COM (Stan Friesen) said:
>> foo((SomeType)(obj1 + obj2));
>> The way I would interpret "end of full expression" in this case makes
>> the call perfectly legitimate as presented. A function call is, itself,
>> an expression, so the largest expression containing the creation of the
>> temporary is the funtion call. This makes the end of the full expression
>> the return from the function.
The interpretation above is correct. For those who want a more
detailed description, I recommend Section 6.3.2 of a new book:
Bjarne Stroustrup: The Design and Evolution of C++, Addson-Wesley.
You will like it.
-- Dag
Author: kanze@us-es.sel.de (James Kanze)
Date: 22 Mar 1994 15:44:28 GMT Raw View
In article <CMoLqC.Hs8@megatest.com> djones@megatest.com (Dave Jones)
writes:
|> From article <1994Mar10.193226.23124@exu.ericsson.se>, by lmcropa@lmc.ericsson.se (Roxsan Payette):
|> > In article <2lnaco$9cv@snlsu1.london.sinet.slb.com>, devitto@anise (Domenico De Vitto) writes:
|> >> djones@megatest.com (Dave Jones) writes:
|> >> : Dear Very Smart Guru,
|> >> : In the following code, what is the guaranteed lifetime of the compiler-
|> >> : generated temporary object created by operator+ ?
|> >> : foo((SomeType)(obj1 + obj2));
|> >> Currently compiler dependant. It should be (says the ANSI comittee) til the
|> >> end of the statement (they use another word, but that's the general idea).
|> >
|> > The other word is "end of full expression" which is not the same thing
|> > as til the end of the statement (although what the ANSI comittee says these
|> > days is not yet part of standard and thus, unsupported by compiler vendors.
|> > The behavior of the statement above is undefined.
|> Given the fact that the C++ compiler itself is free (and eager) to make
|> casts that the programmer did not indicate - that he might not even be
|> aware are possible - this seems like a pretty bad situation. To be safe,
|> it seems to me that the committee should stipulate that the temp object
|> (obj1 + obj2) must survive during the intire call to foo().
They have. Roxsan Payette's statement reflects the current situation,
based on the ARM, not the upcoming standard.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: devitto@anise (Domenico De Vitto)
Date: 10 Mar 1994 14:21:12 GMT Raw View
djones@megatest.com (Dave Jones) writes:
: Dear Very Smart Guru,
:
: Pulleeese answer one or both of the following questions. Please, please,
: please.
:
: In the following code, what is the guaranteed lifetime of the compiler-
: generated temporary object created by operator+ ?
:
: foo((SomeType)(obj1 + obj2));
Currently compiler dependant. It should be (says the ANSI comittee) til the
end of the statement (they use another word, but that's the general idea).
: Question number 2:
:
: How do I write a function prototype that takes an array of pointers
: to character strings as an argument, and promises not to muck with either the
: array of the strings?
This is what Bjarne says: (ish)
const char* const fred;
fred[0]=0; // error
fred="hello"; // error
ie: "const char*" = pointer to constant
"char* const" = constant pointer
"const char* const" = constant pointer to a constant
I think this is what you're after, but I could be wrong....
Dom
Author: lmcropa@lmc.ericsson.se (Roxsan Payette)
Date: Thu, 10 Mar 1994 19:32:26 GMT Raw View
In article <2lnaco$9cv@snlsu1.london.sinet.slb.com>, devitto@anise (Domenico De Vitto) writes:
> djones@megatest.com (Dave Jones) writes:
> : Dear Very Smart Guru,
> :
> : In the following code, what is the guaranteed lifetime of the compiler-
> : generated temporary object created by operator+ ?
> :
> : foo((SomeType)(obj1 + obj2));
>
> Currently compiler dependant. It should be (says the ANSI comittee) til the
> end of the statement (they use another word, but that's the general idea).
The other word is "end of full expression" which is not the same thing
as til the end of the statement (although what the ANSI comittee says these
days is not yet part of standard and thus, unsupported by compiler vendors.
The behavior of the statement above is undefined.
------------------------------------------------------------------------
Roxsan Payette lmcropa@lmc.ericsson.se
CEE Project (LMC/U/LF) Tel. (514) 738-8300 #2508
Ericsson Communication Inc, Montreal Fax. (514) 345-7982
------------------------------------------------------------------------
Author: kanze@us-es.sel.de (James Kanze)
Date: 17 Mar 1994 18:15:15 GMT Raw View
In article <9403150038.AA19682@tdat.ElSegundoCA.NCR.COM>
swf@tdat.ElSegundoCA.NCR.COM (Stan Friesen) writes:
|> In article <1994Mar10.193226.23124@exu.ericsson.se>, lmcropa@lmc.ericsson.se (Roxsan Payette) writes:
|> |> In article <2lnaco$9cv@snlsu1.london.sinet.slb.com>, devitto@anise (Domenico De Vitto) writes:
|> |> > djones@megatest.com (Dave Jones) writes:
|> |> > :
|> |> > : foo((SomeType)(obj1 + obj2));
|> |> >
|> |> > Currently compiler dependant. It should be (says the ANSI comittee) til the
|> |> > end of the statement (they use another word, but that's the general idea).
|> |>
|> |> The other word is "end of full expression" which is not the same thing
|> |> as til the end of the statement ...
|> |>
|> |> The behavior of the statement above is undefined.
|> The way I would interpret "end of full expression" in this case makes
|> the call perfectly legitimate as presented. A function call is, itself,
|> an expression, so the largest expression containing the creation of the
|> temporary is the funtion call. This makes the end of the full expression
|> the return from the function.
Your interpretation agrees with mine. And I believe, that of the
standards committee.
End of full expression was used for cases where the temporary is in
the control expression of a while, for example. End of statement
whould imply that the temporary hang around until the end of the while
loop. So you would get a new temporary each time through the while
loop, and destruct all of them once the loop terminated.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: djones@megatest.com (Dave Jones)
Date: Wed, 9 Mar 1994 02:09:02 GMT Raw View
Dear Very Smart Guru,
Pulleeese answer one or both of the following questions. Please, please,
please.
Question number one is a repeat. Perhaps I rambled on too much.
I'll try to word it more succintly.
In the following code, what is the guaranteed lifetime of the compiler-
generated temporary object created by operator+ ?
foo((SomeType)(obj1 + obj2));
More generally, does a cast of a compiler-generated temporary "dismiss" the
original temporary object, or is the original guaranteed to survive for the
lifetime of the object that it is "cast into" (in this case, the duration of
the procedure call)?
A related "bonus" question is, when does the compiler look on
a cast as a function that returns a new object that stands on its own,
perhaps surviving the object that it is cast from, and when does it look on
the cast as a different way to view the same object (a so-called "pun")?
[I am asking this question because I want to use the operator + from
USL's String package in the initializer section of a constructor, and
the sub-objects being constructed require const char* parameters for
their constructors, not String parameters. But the String must survive
while the subobject is being constructed, because to the way the
String class's operator const char* works.]
Question number 2:
How do I write a function prototype that takes an array of pointers
to character strings as an argument, and promises not to muck with either the
array or the strings?
It would seem that the "safe" function below promises just that.
Indeed the compiler trusts it with arrays that are not supposed to be
written to. But oddly the compiler does not trust it with LESS protected
types -- types that are "less const".
The compiler vendor's documentation says, in effect, "Trust us. We know
what we are doing. The compiler is right to complain." (The actual text is
included below.)
Okay, fine. The question remains, how should I declare the function?
(And a little explaination as to *why* the compiler should complain
would be very helpful. How does the program below "violate const safety"?)
^^^^ snip ^^^^ snip ^^^^ snip ^^^^ snip ^^^^ snip ^^^^ snip ^^^^ snip ^^^^
#include <iostream.h>
typedef const char *ConstCharStar;
void safeFunc(const ConstCharStar stringArray[], int idx)
{
cerr << "stringArray[" << idx << "] == " << stringArray[idx] << endl;
}
int main (int argc, char *argv[])
{
const ConstCharStar dontTreadOnMe[] = {
"One", "Two", "Three"
};
char *goNutsIDontCare[] = {
"One", "Two", "Three"
};
safeFunc(dontTreadOnMe, 2); // Compiler thinks this is just nifty. No prob.
safeFunc(goNutsIDontCare, 2); // Compiler complains, even though this type
// requires *less* const security than the above,
// and the function has promised not to
// write anything into the memory anyway.
// What's the deal?
return (0);
}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#ifdef COMMENT
The compiler says,
"t2.cc", line 40: Warning (Anachronism): Formal argument stringArray of type
const char* const * in call to safeFunc(const char* const *, int)
is being passed char**.
The "migration document" says,
You can usually correct this with an explicit cast, but the error is
probably the result of a logic error. Note that passing a value of type
char** to an argument of type const char** is illegal in both C++ and
ANSI C. This is not an error or oversight in the standard as such
assignments open a hole in the type system and violate const safety.
#endif COMMENT