Topic: Difference between reference vs. poin
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/04/15 Raw View
pstemari@erinet.com (Paul J. Ste. Marie) writes:
>maxtal@Physics.usyd.edu.au (John Max Skaller) wrote:
>:Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>:>
>:>No, you can also get an uninitialized reference like this:
>:> S* p = (S*) malloc(sizeof(S));
>:> // now p->r is an uninitialized reference
>:>
>:>The above code does not have undefined behaviour.
>:
>: Actually, I don't quite agree. After the statement:
>:
>: S* p = (S*) malloc(sizeof(S));
>:
>:is executed, p denotes a PROTO-OBJECT of type S.
>
>Actually, neither is correct. (S*) malloc(sizeof(S)) is casting a
>void* to an type that it doesn't actually point to, and unless I'm
>badly mistaken, counts as undefined behavior even if you didn't
>assign it to anything.
Well, IMHO, you are badly mistaken ;-)
At worst the result would be implementation defined.
I'm not sure exactly what the current draft says, and
in fact I think it may have changed at the last committee meeting.
But I'm pretty sure that regardless of what the current
draft says, there is a consensus amounst the committee members
that code like the above should have well-defined behaviour.
(Amoung other reasons, it's needed for C compatibility! Or at least
it is in the case when S is a POD, and there does not seem to be any
good reason to have different rules for non-PODs.)
>This code is wholly equivalent to
>
> char foo[sizeof(S)]; // well, except for
> S* p = (S*) foo; // alignment issues
I agree. But that code should also be well-defined, IMHO,
if it were not for the alignment issues.
--
Fergus Henderson | As practiced by computer science, the study of
fjh@cs.mu.oz.au | programming is an unholy mixture of mathematics,
http://www.cs.mu.oz.au/~fjh | literary criticism, and folklore. - B. A. Sheil
Author: thp@cs.ucr.edu (Tom Payne)
Date: 1995/04/12 Raw View
Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
: maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
: >Anyhow .. if that is right, we do not really have an uninitialised
: >reference by this mechanism. Of course the case:
: >
: > struct Y {
: > int & x;
: > Y() : x(x) {}
: > };
: >
: >is kind of interesting -- even though "this" does not denote an object
: >it does denote something and you have to be able to use it to
: >access members. So I think here x is an uninitialised reference to
: >itself. I do not know that this is well defined or not.
: >To say it isn't, you have to say "binding a reference to an
: >uninitialised reference is undefined".
Building on this example, consider:
struct Y {
static int & x;
};
extern int i;
int j = 0;
int& Y::x(STUFF);
...
int i = 5;
It appears that there are three distinct disasters that could befall
the reference x :
* It could be used before it is initialized, which would apparently
happen if STUFF were replaced by x.
* It could be initialized to a non-object, which would apparently
happen if STUFF were replaced by *(1+(char*)&i). (I'm assuming
that sizeof(int) > 1.)
* It could be initialized to an uninitialized object, which would
apparently happen if STUFF were replaced by i. (In such cases,
x could get used before the initialization of its referent.)
Also, It appears that the problem of predicting any of these disasters
is recursively unsolvable. For instance, given a function f(fileName)
that purportedly predicts whether or not x gets bound to an
uninitialized object in a given file, simply replace STUFF above by
f( _FILE_ ) ? j : i
to get a non-disaster when and only when f predicts one.
Tom Payne
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/04/11 Raw View
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>>
>>No, you can also get an uninitialized reference like this:
>>
>> int x;
>> struct S {
>> int &r;
>> S() : r(x) {}
>> };
>> S* p = (S*) malloc(sizeof(S));
>> // now p->r is an uninitialized reference
>
>Actually, I don't quite agree.
>[...] It isn't really true p->r is an uninitialised
>reference, the problem is that dereferencing p yields
>a reference to an uninitialised object before one can
>get to the reference r.
You are right.
>Anyhow .. if that is right, we do not really have an uninitialised
>reference by this mechanism. Of course the case:
>
> struct Y {
> int & x;
> Y() : x(x) {}
> };
>
>is kind of interesting -- even though "this" does not denote an object
>it does denote something and you have to be able to use it to
>access members. So I think here x is an uninitialised reference to
>itself. I do not know that this is well defined or not.
>To say it isn't, you have to say "binding a reference to an
>uninitialised reference is undefined".
Actually, you don't - remember that undefined behaviour includes
anything that is simply not defined anywhere, as well as those things
which are explicitly labeled as being undefined.
>Which implicitly admits the existence of uninitialised references :-)
They certainly exist, whether the standard admits it or not ;-)
Another example is
int & f();
int & r = f();
int & f() { return r; }
#include <iostream.h>
main() { cout << r << endl; }
I think it's pretty clear that the draft doesn't define the behaviour
of the above program. (I tried it on one implementation, it printed out
"Segmentation fault" ;-)
--
Fergus Henderson | As practiced by computer science, the study of
fjh@cs.mu.oz.au | programming is an unholy mixture of mathematics,
http://www.cs.mu.oz.au/~fjh | literary criticism, and folklore. - B. A. Sheil
Author: girod@dshp01.trs.ntc.nokia.com (Marc Girod)
Date: 1995/04/10 Raw View
>>>>> "John" == John Max Skaller <maxtal@Physics.usyd.edu.au> writes:
In article <D6nurC.CHx@ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
John> The question being asked is if uninitialised references can
John> exist in well formed/well defined C++ programs.
John> The question was not whether a reference to a non-object can
John> exist (obviously, they can, just dereference a dangling or null
John> pointer: or even more fun, bind a reference to a valid object
John> and then deallocate it).
John> We can say an uninitialised reference exists in a program if
John> the program is well formed but accessing the reference causes
John> its behaviour to be undefined.
John> The question is interesting because the syntax rules of the
John> language attempt to limit the ways in which an uninitialised
John> reference can exist in a well formed program (ideally, it would
John> be impossible to create one, without loss of functionality).
I miss the interest of limiting the ways to have uninititialised
references in well formed programs, once you can have -as you point-
references to non-objects in them...
Why is the question interesting then?
--
+---------------------------------------------------------------------------+
| Marc Girod - Nokia Telecommunications Phone: +358-0-511 27703 |
| TL4E - P.O. Box 12 Fax: +358-0-511 27432 |
| SF-02611 Espoo 61 - Finland Internet: marc.girod@ntc.nokia.com |
| X.400: C=FI, A=Elisa, P=Nokia Telecom, SUR=Girod, GIV=Marc |
+---------------------------------------------------------------------------+
Author: pstemari@erinet.com (Paul J. Ste. Marie)
Date: 1995/04/08 Raw View
In article <D6nurC.CHx@ucc.su.OZ.AU>,
maxtal@Physics.usyd.edu.au (John Max Skaller) wrote:
: I hope you're are mistaken. There is a restriction
:on reinterpreting pointer casts -- the alignment requirements
:of the RHS has to be stronger (bigger) than the LHS>
:
: That it. In particular you are guarranteed that a cast
:from any struct to any other struct via a void* is well defined
:if the initial pointer denotes a suitably aligned address.
:Deferencing the pointer is another story.
So what you're saying is that:
struct bar b;
(struct foo*) (void*) &b;
is well-defined? I can't deny that it is sometimes useful, as is
float foo;
(long&) foo = 0x1234ABCD;
I don't see now this sort of behavior is well-defined, or even how
it could be defined, but I'm not an expert on the ANSI C standard.
It seems like it would simply require that all pointers follow
void* semantics, with possibly some alignment rules tossed into the
mix.
--Paul J. Ste. Marie, pstemari@well.sf.ca.us, pstemari@erinet.com
The Financial Crimes Enforcement Network claims that they capture every
public posting that has their name ("FinCEN") in it. I wish them good hunting.
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/07 Raw View
In article <3m169m$p44@news.erinet.com>,
Paul J. Ste. Marie <pstemari@erinet.com> wrote:
>: Actually, I don't quite agree. After the statement:
>:
>: S* p = (S*) malloc(sizeof(S));
>:
>:is executed, p denotes a PROTO-OBJECT of type S. But there is
>:no object of type S in existence because no S constructor
>:has been run.
>
>Actually, neither is correct. (S*) malloc(sizeof(S)) is casting a
>void* to an type that it doesn't actually point to, and unless I'm
>badly mistaken, counts as undefined behavior even if you didn't
>assign it to anything.
I hope you're are mistaken. There is a restriction
on reinterpreting pointer casts -- the alignment requirements
of the RHS has to be stronger (bigger) than the LHS>
That it. In particular you are guarranteed that a cast
from any struct to any other struct via a void* is well defined
if the initial pointer denotes a suitably aligned address.
Deferencing the pointer is another story.
>Note that no casts are involved, and there are no uninitialized
>references. While you can force uninitialized references through
>casts with undefined behavior, there's nothing particularly odd
>about this.
The question being asked is if uninitialised references
can exist in well formed/well defined C++ programs.
The question was not
whether a reference to a non-object can exist (obviously,
they can, just dereference a dangling or null pointer: or
even more fun, bind a reference to a valid object and then
deallocate it).
We can say an uninitialised reference exists
in a program if the program is well formed but accessing
the reference causes its behaviour to be undefined.
The question is interesting because the syntax
rules of the language attempt to limit the ways in which
an uninitialised reference can exist in a well formed
program (ideally, it would be impossible to create one,
without loss of functionality).
--
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/04/03 Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:
>thp@cs.ucr.edu (tom payne) writes:
>> * There can be uninitialized references (which might sometimes hold
>> have the same bit pattern as the null pointer).
>> * Uninitialized references can be detected at compile time, but the
>> C++ standard doesn't require that they be reported.
>
>No, there cannot be uninitialized references without writing code
>which has undefined results. When a reference is defined, it must
>have an initializer, and the compiler must complain if it doesn't.
>
>The only way to get an "uninitialized reference" would be to declare
> extern T& r;
>and then never provide a definition. In this case, your program might
>not even link.
No, you can also get an uninitialized reference like this:
int x;
struct S {
int &r;
S() : r(x) {}
};
S* p = (S*) malloc(sizeof(S));
// now p->r is an uninitialized reference
The above code does not have undefined behaviour.
In fact, you can go on and initialize the reference now,
using placement new:
new (p) S;
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/04 Raw View
In article <9509400.8620@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>
>No, you can also get an uninitialized reference like this:
>
> int x;
> struct S {
> int &r;
> S() : r(x) {}
> };
> S* p = (S*) malloc(sizeof(S));
> // now p->r is an uninitialized reference
>
>The above code does not have undefined behaviour.
>In fact, you can go on and initialize the reference now,
>using placement new:
>
> new (p) S;
Actually, I don't quite agree. After the statement:
S* p = (S*) malloc(sizeof(S));
is executed, p denotes a PROTO-OBJECT of type S. But there is
no object of type S in existence because no S constructor
has been run. The expression:
*p
would be reference to a non-object, and so the semantics of
p->r
are undefined. It isn't really true p->r is an uninitialised
reference, the problem is that dereferencing p yields
a reference to an uninitialised object before one can
get to the reference r. (*p).r is another way of writing
p->r, and the error is at (*p). not at the 'r'. For example:
struct X { unsigned char x; };
X* p = (X*)malloc(sizeof(X));
p->x; // undefined
new (p) X;
p->x; // unspecified and NOT undefined
The way to think of this is to pretend the class is complicated with
virtual bases and virtual functions -- any attempt to access a member
is undefined because the vtables and virtual base pointers may not
have been layed down.
Anyhow .. if that is right, we do not really have an uninitialised
reference by this mechanism. Of course the case:
struct Y {
int & x;
Y() : x(x) {}
};
is kind of interesting -- even though "this" does not denote an object
it does denote something and you have to be able to use it to
access members. So I think here x is an uninitialised reference to
itself. I do not know that this is well defined or not.
To say it isn't, you have to say "binding a reference to an
uninitialised reference is undefined".
Which implicitly admits the existence of uninitialised references :-)
--
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: thp@cs.ucr.edu (tom payne)
Date: 1995/04/05 Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
: In article <9509400.8620@mulga.cs.mu.OZ.AU>,
: Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
: >
: >No, you can also get an uninitialized reference like this:
: >
: > int x;
: > struct S {
: > int &r;
: > S() : r(x) {}
: > };
: > S* p = (S*) malloc(sizeof(S));
: > // now p->r is an uninitialized reference
: >
: >The above code does not have undefined behaviour.
: >In fact, you can go on and initialize the reference now,
: >using placement new:
: >
: > new (p) S;
: Actually, I don't quite agree. After the statement:
: S* p = (S*) malloc(sizeof(S));
: is executed, p denotes a PROTO-OBJECT of type S. But there is
: no object of type S in existence because no S constructor
: has been run. The expression:
: *p
: would be reference to a non-object, and so the semantics of
There seems to be some ambiguity in the use of the term "object."
Per the ARM, "An object is a region of storage ... The meaning
of the values found in an object is determined by the type
of the expression used to access it." Since *p has a location
and type, it would seem to qualify as an object, even though
the its (uninitialized) bit configuration does not represent
a value in the range of its type.
Tom Payne
Author: pstemari@erinet.com (Paul J. Ste. Marie)
Date: 1995/04/06 Raw View
In article <D6J371.8t5@ucc.su.OZ.AU>,
maxtal@Physics.usyd.edu.au (John Max Skaller) wrote:
:In article <9509400.8620@mulga.cs.mu.OZ.AU>,
:Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
:>
:>No, you can also get an uninitialized reference like this:
:>
:> int x;
:> struct S {
:> int &r;
:> S() : r(x) {}
:> };
:> S* p = (S*) malloc(sizeof(S));
:> // now p->r is an uninitialized reference
:>
:>The above code does not have undefined behaviour.
:>In fact, you can go on and initialize the reference now,
:>using placement new:
:>
:> new (p) S;
:
: Actually, I don't quite agree. After the statement:
:
: S* p = (S*) malloc(sizeof(S));
:
:is executed, p denotes a PROTO-OBJECT of type S. But there is
:no object of type S in existence because no S constructor
:has been run.
Actually, neither is correct. (S*) malloc(sizeof(S)) is casting a
void* to an type that it doesn't actually point to, and unless I'm
badly mistaken, counts as undefined behavior even if you didn't
assign it to anything. This code is wholly equivalent to
char foo[sizeof(S)]; // well, except for
S* p = (S*) foo; // alignment issues
Proper code using placement new would be:
void* temp = malloc(sizeof(S));
S* p = new(temp) S;
Note that no casts are involved, and there are no uninitialized
references. While you can force uninitialized references through
casts with undefined behavior, there's nothing particularly odd
about this.
--Paul J. Ste. Marie, pstemari@well.sf.ca.us, pstemari@erinet.com
The Financial Crimes Enforcement Network claims that they capture every
public posting that has their name ("FinCEN") in it. I wish them good hunting.
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Sat, 25 Mar 1995 06:38:03 GMT Raw View
In article <3ksb11$45c@engnews1.eng.sun.com>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>In article hto@galaxy.ucr.edu, thp@cs.ucr.edu (tom payne) writes:
>
>> * There can be uninitialized references (which might sometimes hold
>> have the same bit pattern as the null pointer).
Yes.
>> * Uninitialized references can be detected at compile time, but the
>> C++ standard doesn't require that they be reported.
I doubt it.
>No, there cannot be uninitialized references without writing code
>which has undefined results. When a reference is defined, it must
>have an initializer, and the compiler must complain if it doesn't.
>
>The only way to get an "uninitialized reference" would be to declare
> extern T& r;
>and then never provide a definition. In this case, your program might
>not even link.
No. It's clear that "r" above might be uninitialised
_even_ if a definition is provided, because initialisation
does not happen all at once. So it is possible to refer
to a reference before it is initialised. Another example is:
struct X {
int x;
int &y;
X() : x(y), y(x) {}
};
It is _also_ possible for a reference to be bound to store
which is not yet an object. So it is not correct that
a reference is bound to an object, a reference is bound to
a memory location. For example:
struct X {
int &y;
int x;
X() : y(x), x(1) {}
};
Change "1" above to "y" and the reference is bound to the
uninitialised x, which is then initialised by itself :-)
It is not at all clear that it is possible to determine
if a reference is bound to an initialised object before
the reference is used.
So -- there are no valid null references BUT there may
well be uninitialised references, or references initialised
to refer to store which is not an object at the time
the references is bound. As far as I know neither of
these circumstances is an error: the reference has to
be "used" for the results to be undefined.
--
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: clamage@Eng.Sun.COM (Steve Clamage)
Date: 23 Mar 1995 17:26:57 GMT Raw View
In article hto@galaxy.ucr.edu, thp@cs.ucr.edu (tom payne) writes:
>Jason Merrill (jason@cygnus.com) wrote:
>
>: Exactly. And so the compiler is not required to diagnose null references,
>: even though they are invalid.
>
>I don't understand what is meant by the term "null reference"?
It's a loose term for a situation that isn't supposed to arise, usually
something equivalent to
T& r = *(T*)0;
so that 'r' doesn't refer to any object. For this to happen, you must
deference a null pointer, which has undefined results.
>It is my understanding that:
> * There can be referrences to pointer variables whose run-time
> value might sometimes be null (a situation whose compile-time
> detection is equivalent to the halting problem).
That would be a reference to a pointer whose value might be null.
That is not a language violation. With any pointer, proper code
must take into account the possibility of it being null.
> * There can be uninitialized references (which might sometimes hold
> have the same bit pattern as the null pointer).
> * Uninitialized references can be detected at compile time, but the
> C++ standard doesn't require that they be reported.
No, there cannot be uninitialized references without writing code
which has undefined results. When a reference is defined, it must
have an initializer, and the compiler must complain if it doesn't.
The only way to get an "uninitialized reference" would be to declare
extern T& r;
and then never provide a definition. In this case, your program might
not even link.
---
Steve Clamage, stephen.clamage@eng.sun.com