Topic: Bind reference to one past end of array
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 26 Jun 1994 22:04:48 GMT Raw View
In article <9417421.687@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>Well, Your Humble Opinion differs from My Humble Opinion on this issue.
It will happen :-)
>
>However, the ARM, then ANSI/ISO working paper, many C++ books,
>and most importantly most compilers agree with MHO rather than YHO.
>
>Are you really suggesting that we rewrite all those books and compilers?
Thats not really an argument. Books, compilers, and WP's
have been wrong or non-ideal before. I dont care nearly as much
what they say as what the underlying principles are and that
they are coherent.
Which is not to say YO is not and MO is.
>
>>> member function call valid object
>>
>> No, only if the function is virtual.
>>Otherwise only valid address is required.
>
>That would also be a change from the existing rules.
No. There are NO existing rules. The ARM rules are too
incoherent to consider as normative. In particular,
the word "object" is not defined. Nor is "valid object" for
that matter.
>It too would causes problems with existing compilers.
How so?
>
>I wrote a program which would be valid under your
>suggested rules but not under the existing rules,
>and tried this with three different C++ implementations
>(g++ 2.5.8, Cfront 2.0, and the ObjectCenter 2.0.4 C++ interpreter).
>None of them executed the program successfully.
I cannot comment unless you show me the program.
However, I cannot elieve that BC4.0 would behave other than
as I suggest, since I have a rough idea how it generates code.
Same for Metaware.
>(ObjectCenter gave a run-time error, the other two ran the program
>but gave incorrect results, namely `assertion failed' rather than
>successful execution.)
YOu aren't telling me anything. How do I know
your code doesnt violate some OTHER rule.
I didnt say the function was permitted to ACCESS the
objects data did I?
>
>Are you suggesting that all these compilers should be modified so that
>they allow my program?
Yes. I'm suggesting it (but I dont know what your
program does).
That doesnt mean its the only or best solution.
I may not even agree with the suggestion.
>>> constructor call (via placement new) valid storage
>>> destructor call valid object
>>
>> No: only if the object is encapsulated.
>>Otherwise only valid address is required.
>
>Well, I need a definition of `encapsulated' before I can discuss that.
A class is encapsulated if:
a) It has a virtual or non-public base, virtual function or nonpublic
member and constructor, or
b) any of its members or bases is encapsulated
All other classes
1) Have no hidden 'vtables' or pointers
2) Grant public access to all data
and thus may be manipulated directly and entirely by the user
in terms of their scalar members -- the thing is just
a data structure. Its unprotected. Such entities can be
copied by memcpy(), encapsulated objects may not be.
>
>> C doesnt have references. C++ requires new rules.
>
>Yes, but it's possible to formulate the new rules so that when applied
>to programs which are both C programs and C++ programs, they give the
>same answers as the rules in C. Furthermore, IMHO that is the way it
>*should* be done, unless there is a very good reason to do it differently.
No its not. Its (almost) possible to formulate the rules
so that well defined C programs remain well defined in C++.
But some non-conforming C programs may be well defined C++.
struct complex { float x,y; };
complex f();
f() = f();
is bad C and legal C++. (For example).
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 27 Jun 1994 17:48:07 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>>
>>Are you really suggesting that we rewrite all those books and compilers?
>
> Thats not really an argument. Books, compilers, and WP's
>have been wrong or non-ideal before. I dont care nearly as much
>what they say as what the underlying principles are and that
>they are coherent.
>
> Which is not to say YO is not and MO is.
There's a big difference between on the one hand wrong or incoherent
and on the other just "non-ideal". I would agree with you that
the current state of affairs is not ideal. But there are quite
coherent underlying principles, and the current state of affairs
works quite well, it's not "wrong".
>>That would also be a change from the existing rules.
>
> No. There are NO existing rules. The ARM rules are too
>incoherent to consider as normative. In particular,
>the word "object" is not defined. Nor is "valid object" for
>that matter.
The ARM may be somewhat incoherent, but by "the existing rules"
I meant the rules of the current de facto standard - i.e.
I also meant what is said in other C++ books and what is allowed
by existing C++ compilers.
>>Are you suggesting that all these compilers should be modified so that
>>they allow my program?
>
> Yes. I'm suggesting it (but I dont know what your
>program does).
>
> That doesnt mean its the only or best solution.
>I may not even agree with the suggestion.
There's a couple of programs at the end of this post,
one of which was the one I mentioned (I forget which).
Under your rules, as I interpret them, both programs
should execute a `return 0' from main().
Under the existing rules, the behaviour is undefined.
Try them with your favourite compilers.
>>>> constructor call (via placement new) valid storage
>>>> destructor call valid object
>>>
>>> No: only if the object is encapsulated.
>>>Otherwise only valid address is required.
With existing compilers, passing only a valid address
can result in undefined behaviour. Have a look at the
`null_this.cc' program that follows - it is checking
for ordinary member function calls, but it would be
easy to adapt for constructors/destructors.
-----------------------------------------------------------------------------
// null_ref.cc
#include <stdlib.h>
#include <assert.h>
struct A { int a; };
struct B { int b; };
struct C : A, B {};
B* f(C* pc) { return pc; }
B& f(C& rc) { return rc; }
int main() {
C* null_ptr = NULL;
B* pb = f(null_ptr);
assert(pb == NULL);
B& rb = f(*null_ptr);
assert(&rb == NULL);
return 0;
}
-----------------------------------------------------------------------------
// null_this.cc
#include <stdlib.h>
#include <assert.h>
struct A {
int a;
};
struct B {
int b;
void foo();
void bar();
};
struct C : A, B {};
C c;
void B::foo() {
assert(this == &c);
}
void B::bar() {
assert(this == NULL);
}
int main() {
C* null_ptr = NULL;
c.foo();
null_ptr->bar();
return 0;
}
-----------------------------------------------------------------------------
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sun, 3 Jul 1994 10:18:49 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>fjh@mundil.cs.mu.OZ.AU (Fergus Henderson) writes:
>
>>Allowing initialization of references with dereferenced null
>>pointers would be confusing and potentially dangerous if
>>you don't also support implicit conversions of references to
>>null pointers.
>
> Why? "allowing null pointers is confusing if you
>dont also allow null references". :-)
There's certainly a grain of truth in that, but the degree of confusion
involved is much less. Programmers expect that dereferencing a null
pointer with `*' or `->' may produce undefined behaviour. They do
*not* expect implicit conversions to produce undefined behaviour - in
fact in many cases they don't even realize that implicit conversions
are occuring, precisely because they are implicit rather than
explicit.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Tue, 28 Jun 1994 15:35:02 GMT Raw View
In article <9417903.20853@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>-----------------------------------------------------------------------------
>
> // null_ref.cc
>
> #include <stdlib.h>
> #include <assert.h>
>
> struct A { int a; };
> struct B { int b; };
> struct C : A, B {};
>
> B* f(C* pc) { return pc; }
Casting NULL must be supported I believe.. Yes?.
> B& f(C& rc) { return rc; }
Casting references isnt.
But this has nothing to do with my argument.
I never said address calculations had to work.
I spoke only of PASSING and DERFERENCING. Not casting.
Sure, casting an *NULL reference will fail.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: fjh@mundil.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 29 Jun 1994 02:55:48 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>> struct A { int a; };
>> struct B { int b; };
>> struct C : A, B {};
>>
>> B* f(C* pc) { return pc; }
>
> Casting NULL must be supported I believe.. Yes?.
Yes, you are allowed to implicitly convert from a null pointer to a class C
to a pointer to a base class B of C, and the result will be a null pointer.
>> B& f(C& rc) { return rc; }
>
> Casting references isnt.
Yes.
> But this has nothing to do with my argument.
>
> I never said address calculations had to work.
There's no explicit address calculations here. I'm just talking about
implicit conversions. The compiler might implement them that way, but
that's not guaranteed, as far as I know.
>I spoke only of PASSING and DERFERENCING. Not casting.
Yes, but argument passing can involve implicit conversion.
Allowing initialization of references with dereferenced null
pointers would be confusing and potentially dangerous if
you don't also support implicit conversions of references to
null pointers.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 1 Jul 1994 18:45:20 GMT Raw View
In article <9418012.5568@mulga.cs.mu.OZ.AU> fjh@mundil.cs.mu.OZ.AU (Fergus Henderson) writes:
>> I never said address calculations had to work.
>
>There's no explicit address calculations here. I'm just talking about
>implicit conversions.
They are address calculations. Or if you prefer,
"I never said implicit conversions were required to work" :-)
>Yes, but argument passing can involve implicit conversion.
>Allowing initialization of references with dereferenced null
>pointers would be confusing and potentially dangerous if
>you don't also support implicit conversions of references to
>null pointers.
Why? "allowing null pointers is confusing if you
dont also allow null references". :-)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 23 Jun 1994 11:14:44 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>> operation required category (IMHO)
>> --------- ------------------------
>> initialize a pointer valid address
>> pointer arithmetic valid address
>> dereference a pointer valid storage [1]
>
> IMHO: only valid address is required.
>
>> initialize a reference valid storage
>
> Again, only valid address required.
> Same as pointer.
Well, Your Humble Opinion differs from My Humble Opinion on this issue.
However, the ARM, then ANSI/ISO working paper, many C++ books,
and most importantly most compilers agree with MHO rather than YHO.
Are you really suggesting that we rewrite all those books and compilers?
>> member function call valid object
>
> No, only if the function is virtual.
>Otherwise only valid address is required.
That would also be a change from the existing rules.
It too would causes problems with existing compilers.
I wrote a program which would be valid under your
suggested rules but not under the existing rules,
and tried this with three different C++ implementations
(g++ 2.5.8, Cfront 2.0, and the ObjectCenter 2.0.4 C++ interpreter).
None of them executed the program successfully.
(ObjectCenter gave a run-time error, the other two ran the program
but gave incorrect results, namely `assertion failed' rather than
successful execution.)
Are you suggesting that all these compilers should be modified so that
they allow my program? I don't think that that would be a good idea.
I'd much rather compiler implementors spend their time doing more
useful things.
>> constructor call (via placement new) valid storage
>> destructor call valid object
>
> No: only if the object is encapsulated.
>Otherwise only valid address is required.
Well, I need a definition of `encapsulated' before I can discuss that.
> C doesnt have references. C++ requires new rules.
Yes, but it's possible to formulate the new rules so that when applied
to programs which are both C programs and C++ programs, they give the
same answers as the rules in C. Furthermore, IMHO that is the way it
*should* be done, unless there is a very good reason to do it differently.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 23 Jun 1994 14:41:46 GMT Raw View
I wrote:
>Well, Your Humble Opinion differs from My Humble Opinion on this issue.
Just in case anyone should get the wrong idea: ------------------> :-)
(I was trying to be vaguely humorous, not arrogant. On re-reading my
post I don't think I succeeded ;-)
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 20 Jun 1994 09:54:30 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
> What do you mean by 'use'?
>Its a sadly abused term. In general for class types "use"
>means "call a virtual member function virtually" or "select a data member
>of scalar type in a context requiring loading a value" or
>"enquire as to the Run Time Type" (and a few other things
>like conversions of pointers to virtual bases).
>
> Everything else is just address calculations not
>requiring access to the object.
There are three categories of operations, not just two.
The first category requires a valid address that refers to a valid region
of storage which is correctly initialized. (Call this ``valid object''.)
The second category requires a valid address that refers to a valid
region of storage, but does not require that the storage be initialized.
(Call this ``valid storage''.)
The third category requires a valid address, but does not require that
the address refer to valid storage. (Call this ``valid address''.)
You can use null pointers and pointers to one past the end of an array
in this category, but not in the first two categories.
Some examples:
operation required category (IMHO)
--------- ------------------------
initialize a pointer valid address
pointer arithmetic valid address
dereference a pointer valid storage [1]
initialize a reference valid storage
member function call valid object
constructor call (via placement new) valid storage
destructor call valid object
copy a char valid storage
copy anything else (e.g. a float) valid object
[1] Perhaps as a special exception, if pointer dereference occurs as
the immediate operand of the builtin `unary &' operator, it might
be treated as only requiring a valid address. I believe that
treating this specially would be an extension to C, since I have
heard that the C standard doesn't allow this. (I might be wrong.)
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Wed, 22 Jun 1994 21:50:36 GMT Raw View
In article <9417119.25323@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>> Everything else is just address calculations not
>>requiring access to the object.
>
>There are three categories of operations, not just two.
>
>The first category requires a valid address that refers to a valid region
>of storage which is correctly initialized. (Call this ``valid object''.)
>
>The second category requires a valid address that refers to a valid
>region of storage, but does not require that the storage be initialized.
>(Call this ``valid storage''.)
>
>The third category requires a valid address, but does not require that
>the address refer to valid storage. (Call this ``valid address''.)
>You can use null pointers and pointers to one past the end of an array
>in this category, but not in the first two categories.
>
>Some examples:
>
> operation required category (IMHO)
> --------- ------------------------
> initialize a pointer valid address
> pointer arithmetic valid address
> dereference a pointer valid storage [1]
IMHO: only valid address is required.
> initialize a reference valid storage
Again, only valid address required.
Same as pointer.
> member function call valid object
No, only if the function is virtual.
Otherwise only valid address is required.
> constructor call (via placement new) valid storage
> destructor call valid object
No: only if the object is encapsulated.
Otherwise only valid address is required.
> copy a char valid storage
> copy anything else (e.g. a float) valid object
Yes, with caveat that a float can be copied using
sizeof(float) chars.
>
>[1] Perhaps as a special exception, if pointer dereference occurs as
> the immediate operand of the builtin `unary &' operator, it might
> be treated as only requiring a valid address. I believe that
> treating this specially would be an extension to C, since I have
> heard that the C standard doesn't allow this. (I might be wrong.)
C doesnt have references. C++ requires new rules.
That may mean an extension to C. but C++ is one big C extension
anyhow. And the C object model and the C++ one are distinct, anyhow.
(C++ notion of value is quite distinct to C's notion)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA