Topic: Proposal for minor changes to standard
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/07/20 Raw View
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>Scott Meyers <smeyers@netcom.com> wrote:
>>I believe the following practices should be errors:
>>
>> - Having a function return a reference to a non-static local object.
>> I'd allow the corresponding pointer practice for compatibility with
>> C. In other words, programs containing functions returning a
>> pointer to a local object would continue to compile, but programs
>> containing functions returning a reference to a non-static local object
>> would not.
>
> Objection #1: Detecting this is not merely onerous but impossible.
You mean that detecting this AT COMPILE TIME is impossible.
Detecting it at run-time is certainly possible and in fact not
hard to implement.
--
Fergus Henderson
fjh@cs.mu.oz.au
http://www.cs.mu.oz.au/~fjh
PGP key fingerprint: 00 D7 A2 27 65 09 B6 AC 8B 3E 0F 01 E7 5D C4 3F
Author: roger@PROCASE.COM (Roger H. Scott)
Date: 1995/07/20 Raw View
In article <3tpi47$m76@f111.iassf.easams.com.au> rjl@f111.iassf.easams.com.au (Rohan LENARD) writes:
>In article <smeyersDB9q18.9ys@netcom.com>,
>Scott Meyers <smeyers@netcom.com> wrote:
>:...
>: inconsistent with the order in which they will actually be
>: initialized.
>:
>: Example:
>:
>: template<class T>
>: class Array {
>: T *data;
>: int size;
>: public:
>: Array(int lowerBound, int upperBound)
>: : size(upperBound-lowerBound+1), // would be an error: size
>: data(new T[size]) // shouldn't be listed before data
>: { ... }
>:
>
>As well as for this -
>
>( gcc-2.7.0 ) -
>bug.cc: In method `Array<int>::Array(int, int)':
>bug.cc:3: warning: member initializers for `int * Array<int>::data'
>bug.cc:4: warning: and `int Array<int>::size'
>bug.cc:9: warning: will be re-ordered to match declaration order
Both of these sort of miss the point, though. The issue isn't really what
order the member initializers are listed in textually. There is only a
problem if the actual expressions used in the initializations result in
used-before-set errors. gcc's auto-reordering doesn't solve this problem,
although the warning message might well lead one to *believe* it has been
solved. "data" will still be initialized with an array whose dimension is
determined by the as-yet-undefined value of "size". On the other hand,
Scott's proposal is *too* strict; in the extremely common cases where there
is no dependency between the member initialization expressions it matters not
at all what order they are listed in. Personally, I think the execution-order-
shall-be-declaration-order rule is a mistake. It just invites trouble.
Wouldn't it be better to leave the initialization order of members unspecified
just like parameters to a function call? Then, just as in that case, the
"quality of implementation" issue would be whether the compiler diagnosed
data flow dependencies on the order of evaluation.
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/07/14 Raw View
In article <smeyersDB9q18.9ys@netcom.com>,
Scott Meyers <smeyers@netcom.com> wrote:
>The ANSI comment period will be up soon, and I can't resist the urge to
>float the following proposals. There are two things that are legal
>in C++ that just strike me as silly, and I can't see how banning them
>outright can do anything but eliminate needless errors. I believe the
>following practices should be errors:
>
> - Having a function return a reference to a non-static local object.
> I'd allow the corresponding pointer practice for compatibility with
> C. In other words, programs containing functions returning a
> pointer to a local object would continue to compile, but programs
> containing functions returning a reference to a non-static local object
> would not.
Objection #1: Detecting this is not merely onerous but impossible.
Therefore no error can be required. The subcase of a reference
bound directly to a local auto isn't worth the effort.
Objection #2: making this an error rather than undefined behaviour
excludes extension to garbage collecting implementations that also
collect function stack frames. Being able to do that is an exceptionally
powerful extension to the language in conjunction with nested functions
(it allows a complete alternate object oriented technique, for example)
> BigInt& operator+(const BigInt& lhs, const BigInt& rhs)
> {
> BigInt sum;
> ...
> return sum; // would be an error if I were King
> }
This is detectable but people RELY on diagnostics.
return *∑
would not require a diagnostic.
> - Listing members in a member initialization list in an order
> inconsistent with the order in which they will actually be
> initialized.
This is detectable. It is a good idea NOT to initialise
things in any way dependent on order. HOWEVER it is a common technique.
However a required diagnostic places a rather heavy burden on
programmers who design classes in which the order is irrelevant.
In particular _minor_ changes to the ordering or use of
virtual bases (for example) might require every constructor in
a lattice to be rewritten.
I suggest this is another quality of implementation issue.
MY OPINION:
The problem with ordering is best solve by permitting
IN CLASS INITIALISERS. I proposed this. Only the trivial and completely
unnecessary case of static member const integral types initialised
by constant expressions was accepted -- an enum can do this job and
do it BETTER because it does not require allocation of storage and it
also flags an error if an enumeration constant is addressed.
It also flags if the initialising value isn't a constant expresssion.
Being able to write:
struct X {
int n = 0;
char *p = 0;
float pi = 22/7.0;
// long list of defaults here
X(int nn) : n(nn), p(malloc(nn+1) {} // pi defaults
X() {} // everything defaults
};
Provides a default set of initialisers presented in order of writing
which is also the order of initialisation. The "current CD" default set
exists and is the default constructor (perhaps trivial) for each type.
This greatly reduces the burden on constructor imnplementations
and thus the propensity to get the order wrong. Amoung other advantages.
--
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: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/07/15 Raw View
smeyers@netcom.com (Scott Meyers) writes:
>Warnings can't be mandated by the standard
Sure they can!
Doing so would not necessarily be a good idea, but it is certainly possible.
--
Fergus Henderson
fjh@cs.mu.oz.au
http://www.cs.mu.oz.au/~fjh
Author: smeyers@netcom.com (Scott Meyers)
Date: 1995/07/12 Raw View
In article <3trdq2$ess@citadel.evolving.com> tblancha@evolving.com (Todd Blanchard) writes:
| Howabout getting the compiler to signal an error on classes with pointer
| members that don't have a user-defined copy constructor/assignment operator?
| This nails people all the time and the compiler generated default
| behavior is almost never what you want. Even a warning would be something.
| Warning on the destructor would also be nice but less critical I think.
Warnings can't be mandated by the standard, and, as you point out,
compiler-generated copy ctors and assignment operators are only ALMOST
always wrong. I've seen classes containing pointers to globals, for
example. I'm afraid I'd have to oppose this, though I understand the
sentiment behind it.
Scott
Author: tblancha@evolving.com (Todd Blanchard)
Date: 1995/07/14 Raw View
Scott Meyers (smeyers@netcom.com) wrote:
: In article <3trdq2$ess@citadel.evolving.com> tblancha@evolving.com (Todd Blanchard) writes:
: | Howabout getting the compiler to signal an error on classes with pointer
: | members that don't have a user-defined copy constructor/assignment operator?
: | This nails people all the time and the compiler generated default
: | behavior is almost never what you want. Even a warning would be something.
: | Warning on the destructor would also be nice but less critical I think.
: Warnings can't be mandated by the standard, and, as you point out,
: compiler-generated copy ctors and assignment operators are only ALMOST
: always wrong. I've seen classes containing pointers to globals, for
: example. I'm afraid I'd have to oppose this, though I understand the
: sentiment behind it.
Well, yes, the idea is for the compiler to help remind us that we have
forgotten something. The impact on the programmer is that he will need to
write the crucial copy constructor, op=, and dtor in all classes with pointer
members. Good programmers write
these as a matter of course. The suggestion is to enlist the compiler's aid
in remembering to write them.
In the not-too-frequent case that the pointer
member in the object is a pointer to something not exclusively owned, the
programmer need only write a copy constructor that provides the usual member-
wise copy. Same for op= and a null destructor. That's not so awful is it?
If you think of it, you're moving the likelihood of an error from the
80-90% of objects that presently get wrong copy constructors to the
10-20% that happen to get correct ones. Compile time safety *is* the idea
isn't it?
Of course, you could never use real pointers and always use something
like auto-ptr for exclusive memory. That gets you automatic destruction.
It also allows copying though so forgetting to properly init it in a copy
constructor is easy to do and catastrophic.
A proper reference counting pointer could mitigate
things, but the standards committee opted not to include one.
The problem with attempting to fix this with an idiom is that there are
several possible behaviors desired:
On copy, a new object is created with the copy constructor,
or a new object is created with the default constructor,
or no new object is desired at this time.
Or if its an array of something - well arrays are a problem because
the lowly pointer object has not idea how long the array is and can't
find out unless it does something like assume null termination or sneaks
a peek at the memory allocator's data.
Better leave it to the compiler/programmer.
Todd Blanchard
Author: shepherd@debussy.sbi.com (Marc Shepherd)
Date: 1995/07/10 Raw View
In article ess@citadel.evolving.com, tblancha@evolving.com (Todd Blanchard) writes:
>Howabout getting the compiler to signal an error on classes with pointer
>members that don't have a user-defined copy constructor/assignment operator?
>This nails people all the time and the compiler generated default
>behavior is almost never what you want. Even a warning would be something.
>Warning on the destructor would also be nice but less critical I think.
>
>What do you think?
Problem is, this isn't always an error--"shallow copy" semantics are
a legitimate idiom (albeit less-often used than "deep copy" semantics).
To flag something as an ERROR (not a warning), you have to believe that
no reasonable program would ever use this idiom. However, this is a
good candidate for a lint++ program to catch, and I believe there are
some commercial lint-like packages which do exactly that.
Note that the standard only specifies what ERRORS an implementation is
required to diagnose; it does *not* specify WARNINGS; this has always
been seen as a "quality of implementation" issue. Besides, if you were
going to make a list of legal but dubious C++ programming practices for
implementations to check, it would be an extremely long list.
---
Marc Shepherd
Salomon Brothers Inc
shepherd@schubert.sbi.com <<These are my opinions, not my employer's.>>
Author: tony@online.tmx.com.au (Tony Cook)
Date: 1995/07/10 Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:
: smeyers@netcom.com (Scott Meyers) writes:
: > - Having a function return a reference to a non-static local object.
: The situation isn't always diagnosable. Example:
: int& foo(int i)
: {
: int a = 0;
: return (i < 0) ? a : i;
: }
: There is nothing wrong with function foo unless you call it with a
: negative value, so IMHO we should not deem the function to be
: ill-formed -- merely "ill-advised :-)
Umm..isn't this just as bad - isn't i a local _copy_ of the actual
parameter (and so will disappear when the function call is
completed).
--
Tony Cook - tony@online.tmx.com.au
100237.3425@compuserve.com
Author: rjl@f111.iassf.easams.com.au (Rohan LENARD)
Date: 1995/07/10 Raw View
This is surely a quality of compiler problem and not a standards problem.
In article <smeyersDB9q18.9ys@netcom.com>,
Scott Meyers <smeyers@netcom.com> wrote:
: - Having a function return a reference to a non-static local object.
: I'd allow the corresponding pointer practice for compatibility with
: C. In other words, programs containing functions returning a
: pointer to a local object would continue to compile, but programs
: containing functions returning a reference to a non-static local object
: would not.
:
: Example:
:
: BigInt& operator+(const BigInt& lhs, const BigInt& rhs)
: {
: BigInt sum;
: ...
: return sum; // would be an error if I were King
: }
There are already compilers which give warnings for this -
( gcc-2.7.0 ) -
bug.cc: In function `class BigInt & operator +(const class BigInt &, const class BigInt &)':
bug.cc:5: warning: reference to local variable `sum' returned
`
(Cfront - 3.0?) -
CC: "xx.cc", line 6: warning: reference to local variable returned (107)
: inconsistent with the order in which they will actually be
: initialized.
:
: Example:
:
: template<class T>
: class Array {
: T *data;
: int size;
: public:
: Array(int lowerBound, int upperBound)
: : size(upperBound-lowerBound+1), // would be an error: size
: data(new T[size]) // shouldn't be listed before data
: { ... }
:
As well as for this -
( gcc-2.7.0 ) -
bug.cc: In method `Array<int>::Array(int, int)':
bug.cc:3: warning: member initializers for `int * Array<int>::data'
bug.cc:4: warning: and `int Array<int>::size'
bug.cc:9: warning: will be re-ordered to match declaration order
Regards,
Rohan
--
----------------------------------------------------------------------------
rjl@iassf.easams.com.au | All quotes can be attributed to my automated quote
Rohan Lenard | writing tool. Yours for just $19.95; and if you
+61-2-367-4555 | call now you'll get a free set of steak knives ...
Author: tblancha@evolving.com (Todd Blanchard)
Date: 1995/07/10 Raw View
Scott Meyers (smeyers@netcom.com) wrote:
: The ANSI comment period will be up soon, and I can't resist the urge to
: float the following proposals. There are two things that are legal
: in C++ that just strike me as silly, and I can't see how banning them
: outright can do anything but eliminate needless errors. I believe the
: following practices should be errors:
So far, I agree with you. These can be sources of subtle bugs that the
compiler could help eliminate. While you're at it:
Howabout getting the compiler to signal an error on classes with pointer
members that don't have a user-defined copy constructor/assignment operator?
This nails people all the time and the compiler generated default
behavior is almost never what you want. Even a warning would be something.
Warning on the destructor would also be nice but less critical I think.
What do you think?
Todd Blanchard
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/07/06 Raw View
smeyers@netcom.com (Scott Meyers) writes:
>The ANSI comment period will be up soon, and I can't resist the urge to
>float the following proposals. There are two things that are legal
>in C++ that just strike me as silly, and I can't see how banning them
>outright can do anything but eliminate needless errors. I believe the
>following practices should be errors:
> - Having a function return a reference to a non-static local object.
The situation isn't always diagnosable. Example:
int& foo(int i)
{
int a = 0;
return (i < 0) ? a : i;
}
There is nothing wrong with function foo unless you call it with a
negative value, so IMHO we should not deem the function to be
ill-formed -- merely "ill-advised :-)
Consider it a "quality of implementation" issue. Some compilers
report the cases which are clearly wrong.
> - Listing members in a member initialization list in an order
> inconsistent with the order in which they will actually be
> initialized.
It sounds like a good idea to me. Why don't you submit it formally?
--
Steve Clamage, stephen.clamage@eng.sun.com
Author: mansionj@lonnds.ml.com (James Mansion LADS LDN X4923)
Date: 1995/07/06 Raw View
In article <3tfqls$ol6@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
>The situation isn't always diagnosable. Example:
>
> int& foo(int i)
> {
> int a = 0;
> return (i < 0) ? a : i;
> }
>
>There is nothing wrong with function foo unless you call it with a
>negative value, so IMHO we should not deem the function to be
>ill-formed -- merely "ill-advised :-)
Well, actually, 'i' and 'a' both have local scope and automatic linkage
so its probably not such a great example. Perhaps you mean 'int& i'
or 'static int a' (the latter from your comment, I guess).
James
--
>Steve Clamage, stephen.clamage@eng.sun.com
Author: smeyers@netcom.com (Scott Meyers)
Date: 1995/07/06 Raw View
The ANSI comment period will be up soon, and I can't resist the urge to
float the following proposals. There are two things that are legal
in C++ that just strike me as silly, and I can't see how banning them
outright can do anything but eliminate needless errors. I believe the
following practices should be errors:
- Having a function return a reference to a non-static local object.
I'd allow the corresponding pointer practice for compatibility with
C. In other words, programs containing functions returning a
pointer to a local object would continue to compile, but programs
containing functions returning a reference to a non-static local object
would not.
Example:
BigInt& operator+(const BigInt& lhs, const BigInt& rhs)
{
BigInt sum;
...
return sum; // would be an error if I were King
}
- Listing members in a member initialization list in an order
inconsistent with the order in which they will actually be
initialized.
Example:
template<class T>
class Array {
T *data;
int size;
public:
Array(int lowerBound, int upperBound)
: size(upperBound-lowerBound+1), // would be an error: size
data(new T[size]) // shouldn't be listed before data
{ ... }
Kindly note that these suggestions are entirely selfless: they'd even
force me to eliminate Item 13 and part of Item 23 from my book,
"Effective C++" :-) Yet I wonder: they may be selfless, but are they
sensible? Other than forcing people who are currently violating these
restrictions to make minor changes to their existing code, is there
some dark side to the above restrictions that I don't see?
Yours in an effort to eliminate gratuitous opportunities for errors,
Scott