Topic: Difference between reference vs. pointer


Author: bpeirce@info.vub.ac.be (Brandon Peirce)
Date: 1995/04/20
Raw View
Mike Rubenstein Phoenix Contract (rubenst%occs.nlm.nih.gov) wrote:
[lots of stuff deleted]
: was definitely unspecified in the Sep 95 draft (I don't hae any earlier ones
[the rest deleted]

How did you manage to get a Sep 95 draft when we are now only in Apr 95???

--
| Brandon Peirce                  bpeirce@info.vub.ac.be |
| Vesalius College of the Vrije Universiteit Brussel     |
| Brussels Free University, BELGIUM                      |





Author: pete@borland.com (Pete Becker)
Date: 1995/04/18
Raw View
In article <KRISS.95Apr18020251@cao-vlsi.ibp.fr>, kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN) says:
>
>When func(int,int) is commutative (something like + or *)
>func(i++,i++) is defined

Not by the C or C++ language definition. This is always an illegal
program. However, it is perfectly legal and, in this case, perhaps
quite appropriate for a compiler vendor to provide a language extension
that produces reasonable code in cases like this; the language requirement
is only that the compiler generate a diagnostic. Code that relies on such an
extension is not portable. That does not necessarily mean that it is bad
code.

> (however it's evaluation order is
>not specified) (i.e. func(3,2) <==> func(2,3)). Such indefinition
>can be VERY usefull in optimising compilers (to perform parallelisation
>or reducing temporaries). I work on a compiler  (precisely a code
>scheduler for superscalars and VLIW processors) that can use such
>undefined behaviour.

Cool!
    -- Pete





Author: kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN)
Date: 1995/04/18
Raw View
When func(int,int) is commutative (something like + or *)
func(i++,i++) is defined (however it's evaluation order is
not specified) (i.e. func(3,2) <==> func(2,3)). Such indefinition
can be VERY usefull in optimising compilers (to perform parallelisation
or reducing temporaries). I work on a compiler  (precisely a code
scheduler for superscalars and VLIW processors) that can use such
undefined behaviour.





Author: rubenst%occs.nlm.nih.gov (Mike Rubenstein Phoenix Contract)
Date: 1995/04/18
Raw View
I (rubenst%occs.nlm.nih.gov) wrote:
> John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>> In article <3lc70s$t1u@hermes.synopsys.com>,
>> Joe Buck <jbuck@synopsys.com> wrote:
>> >
>> >A smart enough compiler could probably diagnose func(i++, i++).

>>  No. Its not allowed to as far as I can tell, the
>> results are unspecified and not undefined.

> No, it's undefined.  From the C standard ISO 6.3:

>  Between the previous and next sequence point an object shall have its
>  stored value modified at most once by the evaluation of the expression.

> There is no sequence point between the two i++ subexpressions, so the
> behavior is undefined.

> Unless there's been a very recent change, this has been carried over to C++.

Thanks to Rob Sartin for pointing out in a private message that this has
indeed been changed in the C++ draft.  The result of an expression in
which an object is modified twice with no guaranteed order of evaluation is
now unspecified.  And it seems that this isn't all that recent change.  It
was definitely unspecified in the Sep 95 draft (I don't hae any earlier ones
available to check if it was changed earlier, but I suspect it was).

In the famous words of Emily Latella, "never mind."

--
Mike Rubenstein





Author: rubenst%occs.nlm.nih.gov (Mike Rubenstein Phoenix Contract)
Date: 1995/04/16
Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
> In article <3lc70s$t1u@hermes.synopsys.com>,
> Joe Buck <jbuck@synopsys.com> wrote:
> >
> >A smart enough compiler could probably diagnose func(i++, i++).

>  No. Its not allowed to as far as I can tell, the
> results are unspecified and not undefined.

No, it's undefined.  From the C standard ISO 6.3:

 Between the previous and next sequence point an object shall have its
 stored value modified at most once by the evaluation of the expression.

There is no sequence point between the two i++ subexpressions, so the
behavior is undefined.

Unless there's been a very recent change, this has been carried over to C++.

--
Mike Rubenstein





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/07
Raw View
In article <3lqhau$o5f@hermes.unt.edu>,
John Robert Williams <johnw@jove.acs.unt.edu> wrote:
>every C++ object has a type/there are no typeless objects. You can often
>pretend that void is a type, but that doesn't make it so.

 But you might consider instead that it is the universal
supertype -- and the resultant type algebra may well be more consistent.

 If you can form a reference to an abstract base,
why not to void? It makes perfect sense. And the reference DOES
denote an object then. And it is useful -- you can take its address.

 Of course like an abstract class you can't have a _value_
of the type, so you can't pass a void value.

 That is -- casting to void, as in:

 int f();
 (void)f();

is a way of _not_ passing a value:

 void g(void);
 g( (void) f() );


In case you don't think void references are useful (WRONG):

 void f() {
  void const &dummy = resource(params);
  // do something
  ..
  // destructor releases resource
 }

Here, I have _deliberately_ made it impossible to access the
resource without a cast. This works, whereas:

 void f() {
  void *p = new resource(params);
   ..
  // woops, not destroyed!
 }

--
        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: chu@prosun.first.gmd.de (Vladimir Chukharev)
Date: 1995/04/07
Raw View
In article <D6HFJt.3vz@ucc.su.OZ.AU>, maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
|> In article <3lc70s$t1u@hermes.synopsys.com>,
|> Joe Buck <jbuck@synopsys.com> wrote:
|> >
|> >A smart enough compiler could probably diagnose func(i++, i++).
|>
|>  No. Its not allowed to as far as I can tell, the
|> results are unspecified and not undefined.
|>

It is allowed, I hope. Even for well defined and well specified

if (i=2){/...

smart compilers give warning (e.g. Cfront).

---
Vladimir Chukharev.
chu@first.gmd.de





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/03
Raw View
In article <3lc70s$t1u@hermes.synopsys.com>,
Joe Buck <jbuck@synopsys.com> wrote:
>
>A smart enough compiler could probably diagnose func(i++, i++).

 No. Its not allowed to as far as I can tell, the
results are unspecified and not 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: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/03
Raw View
In article <3lfb4d$1ki@hermes.synopsys.com>,
Joe Buck <jbuck@synopsys.com> wrote:
>In reference to func(i++, i++),
>maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>> Its NOT undefined. Its merely unspecified.
>
>Since the original point was that such code should be avoided by
>programmers, this detail doesn't matter.

 Its not a detail. It's important. It may or may not
matter that the results are unspecified.

 A topological sort has a post condition in which the
order of entities is unspecified: the order is compatible
with some partial ordering, however, and that may be
all that is required. In that case the fact that the precise
order is unspecified is very very important: it permits
optimisation of the sort algorithm.

 STL contains exactly this distinction in 'sort' and
'stable-sort' algorithms. The stable sort is likely to
be slower.

>>For example:
>>
>> int func(int a, int b) { return a+b; }
>> int i = 1;
>> cout << func(i++,i++);
>>
>>Its well defined result is 3.
>
>This is wrong, John.

 Consider:

 cout << func (++i, ++i);

however the result has to be 2+3. Either the left or right
i can be increment first, but i has to have the value 3 after
the function has been called. So the value of i and result
of the function is well defined even though the order
of evaluation of the arguments are unspecified.

 In the original case, the sequence:

 temp1 = i;
 temp2 = i;
 i++;
 i++;
 func(temp1, temp2)

would indeed yield 2. I'll have to take your word for it that
there is no sequence point between the evaluation of arguments
of a function. (If there were, the results would be well defined
as 3, as I claimed originally -- irrespective of which argument
was evaluated first).

>There's no rule preventing the compiler from
>implementing the operations in an order that would yield 2 as a
>value.  It's not merely that we can process the arguments right
>to left or left to right; we can also interleave the processing
>(something that might happen in cases like this to avoid pipeline
>bubbles, perhaps).

 Are you sure? I'm not sure interleaving is permitted.
That was the whole point of the UK objections.

 In particular, the load modify store operation of i++
is _not_ permitted to be interleaved: the value of i
in the above case is certainly 3 afterwards.

 If we permitted interleaving on a byte level,
the results would certainly be undefined above. And so in
cases like:

 int g();
 func( g(), g() );

g() must be called, return a value, and called again -- two
invocations of g() may not be initiated concurrently.
--
        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: kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN)
Date: 1995/04/04
Raw View
I will sumarize what I answered by mail ito some other people about void.

Right now, void is not a type. It's obvious for many reasons
that were pointed out by different people. But :

1) is there any compiling reason it is so. I don't think so.
2) would it be usefull to do it a real type (with the meaning
 NO TYPE). I think so.
   - an object without type CAN BE USEFULL (as a placeholder
 in fonction parameters, or to reserve some name)
  There comes the *analogy* with zero in math (I never pretended
  to do arithmetics on formal types, so your explanation about
  null sets is pointless)
3) In every respect *except* void, you can do the same things
   with a pointer argument and a reference argument
   (i.e. r <==> *p and &r <==> p). The main difference between
   pointers and references is that calling function is syntaxically
   easyer with references.
4) Why not a *real* void type meaning NO TYPE for objects ?
   NO TYPE for an object should mean the object :
 - has a name (known at compile time)
 - has an address (known at compile time, several strategy could
      be used to give it an address)
    - has NO storage space allocated (so logically sizeof(void)
      should be 0).

It has been pointed out that in most respects void can be considered
as a type but in fact is not. Well, that's exactly what I say.
And I don't like it. Right known void means really nothing.
I feel it has been an error of Ansi C to add it to C language
the way it was. void keyword has *three* different meaning :
- as a return parameter : it means drop return of function.
  much less clean than do not specify type at all...
  but historically no type at all meant 'int'.
- as a fonction parameter : it means no parameter
   not better in any way than an empty list except for emphasis.
- as a pointer type : void * means pointer of any type
 you can store any pointer or address in a void pointer without
 complaint from compiler.

It's not big business. You can do without a clean void type,
you can do without const too (I speak of it because of the
current thread), or even without classes. I regret much more
other leaks in C++.
- you miss a proper nesting of objects
 (by the way what about classes nested in fonctions
  it's ok with g++ (with restrictions)
  it's an error for Visual C++ 2.0)
- you miss a nesting of functions in functions
- you miss a slightly improved preprocessor
- you miss a way to call explicitly constructors
  without allocating space. (to reinitialise an existing object
  and it's base classes) OK, it can be done with init functions
  but it's no nice code.
- you miss a garbage collector (could be limited to garbageable
  classes) typical example product of matrixes.
- you miss a way to design your own operators (C operator set is
  quite limited)
- you miss a way to drop cleanly return levels (it can be done
  but Ifeel it's not easily, nor cleanly).

Those things are what I miss most, I thing every one on this group
could write such a list. Some of those points are difficult to
implement, some are I think very easy.
void problems are much less important, but it's there. I wonder
I am the only one that ever bumped into it.

It is the way it is, OK. But I don't like it and none has yet
pointed out to me any reason I should.

It's not *logic*, it's *choice* (in french i would say 'Erreur humaine').

Sorry, I got ***Flame on*** without even noticing it.





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/04
Raw View
In article <KRISS.95Apr3131550@cao-vlsi.ibp.fr>,
Christophe GROSJEAN <kriss@cao-vlsi.ibp.fr> wrote:
>
>I think my previous Posting was not well understood,
>It's all about the meaning of 'void'
>
>When you use a pointer of type 'void *' it's in every cases
>(i can't imagine any other case) that you mean it as a pointer
>of 'any type', I never saw a case where it was intended as
>'no type at all'.
>
>Well, clearly enough you can't have a variable of type void,
>whatever the meaning compiler can't allocate space for such
>a variable (or may be not allocate space at all, in such
>way to say to compiler to 'drop' a parameter it void appears
>in a header, but that's not the point...)
>
>A reference to void (say void & rv) is another matter,
>it could mean (and it should to be homogeneous with pointers)
>'a variable of any type'. Such a variable could behave
>exactly like a void pointer : you can't access it's value
>'cause value of a void means nothing.
>But address of a variable means something, more than that
>i think that when you write &v where v is a reference,
>you get the address of the original variable refered to
>(am i wrong ?, i will check in ARM). So I can't see any
>reason why you should'nt use reference to void as a type.

 Excellent point.
>
>I can't even see in second thought why void type is forbidden
>(with the meaning explained above : no space allocated !)

 After reading your analysis it is hard to disagree.

>Right now, I believe that is forbidden for no practical reason,
>but from misconception 'cause meaning of void is not obvious,
>and has not been really in depth considered when added to ANSI C,
>and as not been given a thought when ported to C++.

 It is related to the restriction on zero length objects
and distinct addresses.
>
>Indeed void type is not of great use, it's just one of the many
>irregularities of C++.

 No. Boundary conditions like this are crucial in
determining the overall topology of the language on which
templates rely directly.

 Deciding for or against void types is not a minor
issue -- it is a fundamental question that is a _principle_
determinant of the character of the type system.

 That is, a type system with only ONE type T, pointers
and references and void is all that is of any interest
topologically because generalising from one type T to types
T1 T2 T3 ... is trivial.

 Exactly what to do with void is then seen to be
far MORE important than having more than one type (say int)
in the language.

 The same can be said of the distinction between
built-in types and class types. You only need one of each
to consider the algebraic structure of the system.

 ... which is all a way of saying I think I have learned
something from what you wrote and it is not as unimportant -- IMHO --
as you think. :-)


--
        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: kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN)
Date: 1995/04/04
Raw View
What's weird with
sizeof(void) == sizeof(void&) ?

It's not allowed, OK. It's a choice.

But it's not weird.
Try :

void * p;
sizeof(*p); // == sizeof(void)

It's not allowed either !
But the same expression would be OK
with any other type than void.
THAT is weird.

I would prefer sizeof(void) == 0.
(Or do not keep void type in C++).

I think the problem with void is the same as the problem
of the number zero in Maths.

It took a long time before people accepted there WAS such thing
as a 'no number'... and that it is USEFULL.





Author: johnw@jove.acs.unt.edu (John Robert Williams)
Date: 1995/04/04
Raw View
Christophe GROSJEAN (kriss@cao-vlsi.ibp.fr) wrote:

> What's weird with
> sizeof(void) == sizeof(void&) ?

> It's not allowed, OK. It's a choice.

> But it's not weird.
> Try :

> void * p;
> sizeof(*p); // == sizeof(void)

> It's not allowed either !
> But the same expression would be OK
> with any other type than void.
> THAT is weird.

> I would prefer sizeof(void) == 0.
> (Or do not keep void type in C++).

> I think the problem with void is the same as the problem
> of the number zero in Maths.

> It took a long time before people accepted there WAS such thing
> as a 'no number'... and that it is USEFULL.

You seem to misunderstand the meanings of both 0 and void. They are not
anlagous. Think of it this way: {} (a null set) is no number, and 0 is a
number representing nothing. void is NO TYPE, and this no type that is
nothing, since this would be useless. All problems with void go away when
you consider that is IS NOT a type. It's the lack of a type. The reason
you can't have a void& is because you can't have a void object because
every C++ object has a type/there are no typeless objects. You can often
pretend that void is a type, but that doesn't make it so.

John Williams
johnw@jove.acs.unt.edu
"Life is case sensitive."






Author: mikes@forte.com (Mike Schilling)
Date: 1995/04/06
Raw View
Christophe GROSJEAN (kriss@cao-vlsi.ibp.fr) wrote:
: By the way, can anybody explains why the header foo(void & p) is illegal ?
: A long time ago, I too thought references were merely a short notation
: for implicit pointers. If it were the case the above header should be ok
: as foo(void * p) is ok.

Think of a reference as a pointer that's always dereferenced (Stroustrup
suggests this in _The C++ Programming Language_).  You can't dereference
a void pointer, thus you can't have a void reference.  (You can dereference
the vpoid pointer after casting it to something else, of course, but then it's
no longer a void pointer.)

Mike





Author: kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN)
Date: 1995/04/03
Raw View
I think my previous Posting was not well understood,
It's all about the meaning of 'void'

When you use a pointer of type 'void *' it's in every cases
(i can't imagine any other case) that you mean it as a pointer
of 'any type', I never saw a case where it was intended as
'no type at all'.

Well, clearly enough you can't have a variable of type void,
whatever the meaning compiler can't allocate space for such
a variable (or may be not allocate space at all, in such
way to say to compiler to 'drop' a parameter it void appears
in a header, but that's not the point...)

A reference to void (say void & rv) is another matter,
it could mean (and it should to be homogeneous with pointers)
'a variable of any type'. Such a variable could behave
exactly like a void pointer : you can't access it's value
'cause value of a void means nothing.
But address of a variable means something, more than that
i think that when you write &v where v is a reference,
you get the address of the original variable refered to
(am i wrong ?, i will check in ARM). So I can't see any
reason why you should'nt use reference to void as a type.

I can't even see in second thought why void type is forbidden
(with the meaning explained above : no space allocated !)

Right now, I believe that is forbidden for no practical reason,
but from misconception 'cause meaning of void is not obvious,
and has not been really in depth considered when added to ANSI C,
and as not been given a thought when ported to C++.

Indeed void type is not of great use, it's just one of the many
irregularities of C++. I believe adding this type with the meaning
said above is not great bother to compiler's write, would not
break code, and could even simplify compilers !

Thanks for any advice.





Author: tony@online.tmx.com.au (Tony Cook)
Date: 1995/04/03
Raw View
Christophe GROSJEAN (kriss@cao-vlsi.ibp.fr) wrote:

: By the way, can anybody explains why the header foo(void & p) is illegal ?
: A long time ago, I too thought references were merely a short notation
: for implicit pointers. If it were the case the above header should be ok
: as foo(void * p) is ok.

Now you know:
 sizeof(T&) == sizeof(T)

So apply to 'void &':

 sizeof(void &) == sizeof(void) ????

and other similar wierdness.


--
        Tony Cook - tony@online.tmx.com.au
                    100237.3425@compuserve.com





Author: jbuck@synopsys.com (Joe Buck)
Date: 1995/03/30
Raw View
In reference to func(i++, i++),
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
> Its NOT undefined. Its merely unspecified.

Since the original point was that such code should be avoided by
programmers, this detail doesn't matter.

>For example:
>
> int func(int a, int b) { return a+b; }
> int i = 1;
> cout << func(i++,i++);
>
>Its well defined result is 3.

This is wrong, John.  There's no rule preventing the compiler from
implementing the operations in an order that would yield 2 as a
value.  It's not merely that we can process the arguments right
to left or left to right; we can also interleave the processing
(something that might happen in cases like this to avoid pipeline
bubbles, perhaps).


--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729





Author: chu@prosun.first.gmd.de (Vladimir Chukharev)
Date: 1995/03/31
Raw View
In article <3l5t09$7qu@bmdhh222.bnr.ca>, dbinder@bnr.ca (David Binderman) writes:
|> Joe Buck (jbuck@synopsys.com) wrote:
|> : There is nothing new about this in C or C++.  There are many constructs
|> : whose behavior is undefined: func(i++, i++) for example.  Many of these
|> : are not checked by must compilers.  Programmers are on their honor not
|> : to write code that has two side effects between sequence points (though
|> : as far as I know the C++ gang hasn't imported sequence points from C yet).
|>
|> Any interest in making it mandatory for the compiler to produce
|> a diagnostic for these kind of undefined behaviours ?

|>
|> Regards
|>
|> David C Binderman MSc BSc  dbinder@bnr.ca  dbinder@bnr.co.uk  +44 1628 794 887
|> Object Oriented Design & Analysis with C++, UNIX and C.

Yes. I experienced many cases of helping novices finding such errors
in C. And remember twice being cought myself. Would be great to have
a switchable warning for it.

V.Chukharev.
chu@first.gmd.de





Author: kriss@cao-vlsi.ibp.fr (Christophe GROSJEAN)
Date: 1995/03/31
Raw View
> If I understand correctly, one may think of a reference as a pointer
> constant that is automatically dereferenced whenever it is used --
> imagine an ninvisible * in front of it.  In the code above, a
> reference to the pointer variable p is being passed, at a time when
> the current value of p happens to be NULL.  Were it possible to see
> the value of the reference itself (as opposed to its referent p), one
> would find that its value is the address of p, which can never be
> NULL.

Why not ? If you only use &p in your code, it may even be correct.

By the way, can anybody explains why the header foo(void & p) is illegal ?
A long time ago, I too thought references were merely a short notation
for implicit pointers. If it were the case the above header should be ok
as foo(void * p) is ok.

I speak of it because I wrote code that needed a variable of type void
(real type was explicitely transmited by some other way as an int).
I had to use a void * instead of a void &, cause the later construct
seems forbidden.





Author: chu@prosun.first.gmd.de (Vladimir Chukharev)
Date: 1995/03/31
Raw View
In article <796311505snz@doughnut.demon.co.uk>, Alan@doughnut.demon.co.uk (Alan Bellingham) writes:
|> In article <3l5t09$7qu@bmdhh222.bnr.ca> dbinder@bnr.ca "David Binderman" writes:
|>
|> > Joe Buck (jbuck@synopsys.com) wrote:
|> > : There is nothing new about this in C or C++.  There are many constructs
|> > : whose behavior is undefined: func(i++, i++) for example.  Many of these
|> > : are not checked by must compilers.  Programmers are on their honor not
|> > : to write code that has two side effects between sequence points (though
|> > : as far as I know the C++ gang hasn't imported sequence points from C yet).
|> >
|> > Any interest in making it mandatory for the compiler to produce
|> > a diagnostic for these kind of undefined behaviours ?
|>
|> It's not always possible for a compiler to know that you are invoking
|> undefined behaviour. Consider, in two different translation units:
|>
|>     foo ( i, i ) ;
|>
|>
|>     void foo ( int& i, int& j )
|>     {
|>        printf ( "%d %d", i++, j++ ) ;
|>     }


Isn't it possible to warn against double use of a variable
in 'non-const' reference (and pointer) parameters list?
Of course, as optional warning?

Real problem can arise with overlapping arrays. I'd like
to have some construct to tell compiler there is no aliasing.
May be declare param with special attribute, and force
every (or only suspicious) call to use special cast (to remind):


int x[10];

void f(noalias int* a, int* b){ /*...*/}
//...
f(noalias_cast(x), &x[5]);


Yes, each new keyword is evels. One can be used here for both, but still...
Well, let's wait for C standard, someone just said they work on this and
C++ will follow.

Vladimir Chukharev
chu@prosun.first.gmd.de





Author: jbuck@synopsys.com (Joe Buck)
Date: 1995/03/29
Raw View
I wrote:
>: There is nothing new about this in C or C++.  There are many constructs
>: whose behavior is undefined: func(i++, i++) for example.  Many of these
>: are not checked by must compilers.  Programmers are on their honor not
>: to write code that has two side effects between sequence points (though
>: as far as I know the C++ gang hasn't imported sequence points from C yet).

dbinder@bnr.ca (David Binderman) writes:
>Any interest in making it mandatory for the compiler to produce
>a diagnostic for these kind of undefined behaviours ?

A smart enough compiler could probably diagnose func(i++, i++).  But the
problem of diagnosing the creation of null references is exactly the same
as the problem of proving at compile time that no null pointer is ever
dereferenced.  With separate compilation, there's no hope of doing this;
even if you can see everything, it is an undecidable problem.

Similarly, what about func(foo(), bar()) where both foo and bar access
and modify the same global variable, but the compiler can't see this
because foo and bar are compiled separately?

Still, compilers can certainly catch *some* cases.  Call it a quality
of implementation issue.

--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/03/30
Raw View
In article <D64zH0.8GF@cwi.nl>, Olaf Weber <olaf@cwi.nl> wrote:
>In article <D649Ly.Fpw@ucc.su.OZ.AU>, maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>
>> For example:
>
>>  int func(int a, int b) { return a+b; }
>>  int i = 1;
>>  cout << func(i++,i++);
>
>> Its well defined result is 3.
>
>That means that in this the C++ standard-to-be diverges from the ANSI
>C standard.  According to the latter, the call `func(i++,i++)' would
>lead to undefined behaviour.

 I believe that is the case but what the final Standard says
may differ from what the WP says now.

 Feb WP, 1.8 Program Execution [intro.execution] para 3:

 "Certain other aspects of the abstract machine are described
 in this Standard as unspecified (for example the order of
 evaluation of arguments to a function). In each case the
 Standard defines a set of alloawable behaviours.
 These define the nondeterministic aspects of the abstract
 machine. An instance of the abstract machine can thus
 have more than one possible execution sequence for a given
 program and a given input."


 It is my understanding you can analyse sequence points
in terms of examining all cases: the results are always
merely unspecified because the ordering of the operations
is merely unspecified -- not undefined.

 This issue was raised by the UK in relation to
parallel execution -- which the current WP wording appears
to rule out in some cases exactly because the results are
unspecified and not undefined. That is, a conforming
C++ implementation must chose one possible sequence
of evaluation of:

 f(i++,i++)

which guarrantees i is incremented twice --
it is NOT permitted to execute the two "i++" in parallel,
which may result in i only being incremented once.

Note again -- DO NOT RELY on this until we have an International Standard.

In particular, if you don't like it, say so during public review.

[I think the decision is resonable myself, because C++ is
intended for a machine with a single thread of control]

--
        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: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Mon, 27 Mar 1995 20:44:22 GMT
Raw View
In article <3l5t09$7qu@bmdhh222.bnr.ca>,
David Binderman <dbinder@bnr.ca> wrote:
>Joe Buck (jbuck@synopsys.com) wrote:
>: There is nothing new about this in C or C++.  There are many constructs
>: whose behavior is undefined: func(i++, i++) for example.  Many of these
>: are not checked by must compilers.  Programmers are on their honor not
>: to write code that has two side effects between sequence points (though
>: as far as I know the C++ gang hasn't imported sequence points from C yet).

 Yes we have.
>
>Any interest in making it mandatory for the compiler to produce
>a diagnostic for these kind of undefined behaviours ?

 Its NOT undefined. Its merely unspecified.
For example:

 int func(int a, int b) { return a+b; }
 int i = 1;
 cout << func(i++,i++);

Its well defined result is 3.

In any case there is nothing particularly wrong with a program
that could have one of several behaviours. "Give me a prime
number between 10000000000 and 10000000000000000".
I didn't specify which one. I don't care -- it doesn't matter.

--
        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: olaf@cwi.nl (Olaf Weber)
Date: Tue, 28 Mar 1995 06:03:17 GMT
Raw View
In article <D649Ly.Fpw@ucc.su.OZ.AU>, maxtal@Physics.usyd.edu.au (John Max Skaller) writes:

> For example:

>  int func(int a, int b) { return a+b; }
>  int i = 1;
>  cout << func(i++,i++);

> Its well defined result is 3.

That means that in this the C++ standard-to-be diverges from the ANSI
C standard.  According to the latter, the call `func(i++,i++)' would
lead to undefined behaviour.

-- Olaf Weber




Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 28 Mar 1995 14:31:20 GMT
Raw View
In article <D64zH0.8GF@cwi.nl> olaf@cwi.nl (Olaf Weber) writes:

|> In article <D649Ly.Fpw@ucc.su.OZ.AU>, maxtal@Physics.usyd.edu.au (John Max Skaller) writes:

|> > For example:

|> >  int func(int a, int b) { return a+b; }
|> >  int i = 1;
|> >  cout << func(i++,i++);

|> > Its well defined result is 3.

|> That means that in this the C++ standard-to-be diverges from the ANSI
|> C standard.  According to the latter, the call `func(i++,i++)' would
|> lead to undefined behaviour.

I believe that this is still the case in C++, too.

There has been some talk of changing the wording, so that the compiler
is *not* allowed to reformat the disk, for example.  But there is
certainly nothing that would allow the assertion that the results must
be 3.  I can think of a perfectly reasonable implementation
(conforming) in which the results were 2, for example.
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: rubenst%occs.nlm.nih.gov (Mike Rubenstein Phoenix Contract)
Date: Tue, 28 Mar 95 13:54:44 GMT
Raw View
David Binderman (dbinder@bnr.ca) wrote:
> Joe Buck (jbuck@synopsys.com) wrote:
> : There is nothing new about this in C or C++.  There are many constructs
> : whose behavior is undefined: func(i++, i++) for example.  Many of these
> : are not checked by must compilers.  Programmers are on their honor not
> : to write code that has two side effects between sequence points (though
> : as far as I know the C++ gang hasn't imported sequence points from C yet).

> Any interest in making it mandatory for the compiler to produce
> a diagnostic for these kind of undefined behaviours ?

How?  It's obvious in cases like this, but suppos we had

 func((*p)++, (*q)++);

If p and q point to the same int object, this results in undefined behavior;
if they point to different int objects, it is defined.

It's very difficult to specify precisely when such diagnostics are required
in any useful way.

--
Mike Rubenstein




Author: jbuck@synopsys.com (Joe Buck)
Date: 24 Mar 1995 22:48:35 GMT
Raw View
kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763) writes:
>The C standard refers to the above cases as "undefined behavior".
>This means that no matter what happens as a result, it is not the
>implementations fault.

Undefined behavior means that absolutely anything can happen.  Richard
Stallman took advantage of this in an early version of gcc.  Should the
input contain a #pragma directive (documented as undefined behavior in
ANSI C), gcc would start a game of "rogue" or "hack".  I'm not kidding.

Now that gcc actually has pragmas, the fun is gone.



--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729




Author: thp@cs.ucr.edu (tom payne)
Date: 26 Mar 1995 22:29:55 GMT
Raw View
Joe Buck (jbuck@synopsys.com) wrote:
: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763) writes:
: >The C standard refers to the above cases as "undefined behavior".
: >This means that no matter what happens as a result, it is not the
: >implementations fault.

: Undefined behavior means that absolutely anything can happen.  Richard
: Stallman took advantage of this in an early version of gcc.  Should the
: input contain a #pragma directive (documented as undefined behavior in
: ANSI C), gcc would start a game of "rogue" or "hack".  I'm not kidding.

: Now that gcc actually has pragmas, the fun is gone.


"The '#pragma' command is specified in the ANSI standard to have an
arbitrary implementation-defined effect.  In the GNU C preprocessor,
'#pragma' first attempts to run the game 'rouge'; if that fails, it
tries to run the game 'hack'; if that fails, it tries to run GNU Emacs
displaying the Tower of Hanoi; if that fails, it reports a fatal
error.  In any case, preprocessing does not continue."

-- Manual for the GNU C preporcessor for GNU CC 1.34.





Author: dbinder@bnr.ca (David Binderman)
Date: 27 Mar 1995 08:28:57 GMT
Raw View
Joe Buck (jbuck@synopsys.com) wrote:
: There is nothing new about this in C or C++.  There are many constructs
: whose behavior is undefined: func(i++, i++) for example.  Many of these
: are not checked by must compilers.  Programmers are on their honor not
: to write code that has two side effects between sequence points (though
: as far as I know the C++ gang hasn't imported sequence points from C yet).

Any interest in making it mandatory for the compiler to produce
a diagnostic for these kind of undefined behaviours ?

Regards

David C Binderman MSc BSc  dbinder@bnr.ca  dbinder@bnr.co.uk  +44 1628 794 887
Object Oriented Design & Analysis with C++, UNIX and C.





Author: Alan@doughnut.demon.co.uk (Alan Bellingham)
Date: Mon, 27 Mar 1995 13:38:25 +0000
Raw View
In article <3l5t09$7qu@bmdhh222.bnr.ca> dbinder@bnr.ca "David Binderman" writes:

> Joe Buck (jbuck@synopsys.com) wrote:
> : There is nothing new about this in C or C++.  There are many constructs
> : whose behavior is undefined: func(i++, i++) for example.  Many of these
> : are not checked by must compilers.  Programmers are on their honor not
> : to write code that has two side effects between sequence points (though
> : as far as I know the C++ gang hasn't imported sequence points from C yet).
>
> Any interest in making it mandatory for the compiler to produce
> a diagnostic for these kind of undefined behaviours ?

It's not always possible for a compiler to know that you are invoking
undefined behaviour. Consider, in two different translation units:

    foo ( i, i ) ;


    void foo ( int& i, int& j )
    {
       printf ( "%d %d", i++, j++ ) ;
    }

Alan Bellingham
--
Alan@doughnut.demon.co.uk         "It's almost impossible to ride a rock
Work +44(0)1763-262629                and roll motorbike and stay on for
Home +44(0)1223-413759             three verses." Terry Pratchett on afp




Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 22 Mar 1995 14:22:25 GMT
Raw View
In article <mikeq.170.002D3703@primenet.com> mikeq@primenet.com
(Michael Quinlan) writes:

|> In article <3ki0bi$oqt@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:

|> >The only way to try to make a "null reference" is to dereference a
|> >null pointer, the results of which are undefined. You have no
|> >business writing code which dereferences a pointer which could be null.

|> >(Please, no arguments about whether the compiler has to generate
|> >code to dereference 'p' above. Whether it must do so or not is
|> >an implementation detail, not part of the language definition.)

|> >If you prefer the belt-and-braces style of programming, you certainly
|> >can check your references for null if you want to.

|> >By contrast, a reliable program MUST check a pointer argument for null.

|>     I appreciate your response, and that of others, but to be honest, I am a
|>     bit troubled by this. Others have posted the part of the standard which
|>     says it that a reference cannot be NULL, but also says that no warning is
|>     required.

The standard does not require a warning, because requiring one would
result in run-time overhead on many systems.  But it certainly does
not forbid one, and the compiler I use at one of my customer sites
(Green Hills) *will* generate the run-time check.  I suspect that if
the market ever starts placing quality over putting the most features
on the smallest machine possible, other compilers will do the same.

|>     That means that programmers are on the "honor system" to not use the
|>     sort of code listed above. Won't this almost certainly result in
|>     unreliable code? Programmers are human beings who will make mistakes
|>     even when they understand the details of the standard.

There are (regrettably) lots of features in C++ (and C) which result
in undefined behavior, and even work on many machines.  For many
years, most Unix linkers put a page of 0's at the beginning of the
program; dereferencing a NULL pointer actually worked on such
machines.  Programmers on such machines were on the honor system not
to do so.  (When we changed this `feature' at one customer site, about
a third of the Unix utilities core-dumped:-).)  And of course, in
native mode on MS-DOS machines, you can not only read, but also write
through a NULL pointer.

This is one of the major features of C; in so far as C++ tries to
maintain some degree of C compatibility, it will probably remain a
feature of C++.  If you really don't like this, you will have to try a
different language.  (As a consultant who makes his money off other
peoples problems, I find this a very rewarding feature:-).)
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 22 Mar 1995 17:53:50 GMT
Raw View
In article <3kjdtg$77e@cpccux0.cityu.edu.hk> ccwup@$MAILHOST (WU
Sheung Chau) writes:

|> >>>>>Jason Merrill (jason@cygnus.com) wrote:
|> : Please justify your statement.  How is
|> : void f (char&);
|> : main () { f (*(char*)0); }
|> : different from
|> : main () { char &r = *(char*)0; }
|> : ?
|> : Jason
|> Sorry, I don't know what you want me to justfy.

|> Perhaps I have misinterpreted your last news.
|> So do you mean both code portions above will not pass the compiler?

No.  In the quote from the standard that you cut, it states explicitly
that no diagnostic is required.

Accessing a non-initialized variable is illegal.  No diagnostic is
required.  Dereferencing a NULL pointer is illegal.  No diagnostic is
required.  There are a number of illegal operations for which no
diagnostic is required.  They are still illegal.

The C standard refers to the above cases as "undefined behavior".
This means that no matter what happens as a result, it is not the
implementations fault.

Good compilers will generate code which detects such code (at
run-time).  But as this will result in slower programs, it will
generally be possible to turn off the run-time checking.  At your own
risk.
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: jbuck@synopsys.com (Joe Buck)
Date: 22 Mar 1995 19:34:47 GMT
Raw View
mikeq@primenet.com (Michael Quinlan) writes:
>    I appreciate your response, and that of others, but to be honest, I am a
>    bit troubled by this. Others have posted the part of the standard which
>    says it that a reference cannot be NULL, but also says that no warning is
>    required.
>
>    That means that programmers are on the "honor system" to not use the
>    sort of code listed above.

There is nothing new about this in C or C++.  There are many constructs
whose behavior is undefined: func(i++, i++) for example.  Many of these
are not checked by must compilers.  Programmers are on their honor not
to write code that has two side effects between sequence points (though
as far as I know the C++ gang hasn't imported sequence points from C yet).

> Won't this almost certainly result in unreliable code?

What it means is that reliable code must check pointers for NULL *before*
converting them to references.  If this weren't done, reliable code would
have to check references for NULL before dereferencing.  There are still
going to be the same number of checks required.  The advantage of having
references always non-null

> Programmers are human beings who will make mistakes
>    even when they understand the details of the standard.

But if this rule weren't there then code like the following would be
unsafe:

void func(Object & foo) {
 foo.method();
}

because foo might be a null reference.  Programmers have written tons of
this stuff.  That is, programmers are already writing most code with the
assumption that references are non-NULL.  The committee is really blessing
current practice.

The only point where a programmer needs to check is in cases like

Object * optr;

func(*optr);  // unsafe

Here a (possibly null) pointer is converted into a reference.  I could
imagine some type of "checkout" environment that would effectively insert
"if (!optr) throw null_reference;" or something.  Requiring compilers to
do this, though, would be wildly inefficient.



--
-- Joe Buck  <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Phone: +1 415 694 1729




Author: thp@cs.ucr.edu (tom payne)
Date: 23 Mar 1995 01:51:26 GMT
Raw View
Jason Merrill (jason@cygnus.com) wrote:
: >>>>> WU Sheung Chau <ccwup@> writes:

: >  whether the object being refered is valid is usually
: >  cannot be determined during compilation.

: Exactly.  And so the compiler is not required to diagnose null references,
: even though they are invalid.

: Jason


I don't understand what is meant by the term "null reference"?

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).
 *  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.
 *  Uninitialized references cannot be diagnosed at run time, unless
    the compiler writer takes special care to preinitialize them with
    some special value.


Tom Payne




Author: jason@cygnus.com (Jason Merrill)
Date: 17 Mar 1995 18:48:15 GMT
Raw View
>>>>> WU Sheung Chau <ccwup@> writes:

> Jason Merrill (jason@cygnus.com) wrote:

> : From the current WP:

> :   8.3.2  References                                            [dcl.ref]

> : 4         A reference  shall  be
> :   initialized  to  refer  to a valid object or function.  In particular,
> :   null references are prohibited; no diagnostic is required.

> I am afraid that the sentences quoted by Jason only applies to the case
> of declaring a reference variable

Please justify your statement.  How is

void f (char&);
main () { f (*(char*)0); }

different from

main () { char &r = *(char*)0; }

?

Jason




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 19 Mar 1995 19:23:30 GMT
Raw View
mikeq@primenet.com (Michael Quinlan) writes:


>    It is certainly possible to pass a NULL as a reference. Code fragment:

>    void yourfunc(int& r);

>    int* p = NULL;
>    yourfunc(*p);

>    I don't know if the behavior of this code fragment is defined by the
>    proposed standard.

The behavior of this code is undefined. Any function taking a reference
parameter is allowed to assume that the reference is real.

The only way to try to make a "null reference" is to dereference a
null pointer, the results of which are undefined. You have no
business writing code which dereferences a pointer which could be null.

(Please, no arguments about whether the compiler has to generate
code to dereference 'p' above. Whether it must do so or not is
an implementation detail, not part of the language definition.)

If you prefer the belt-and-braces style of programming, you certainly
can check your references for null if you want to.

By contrast, a reliable program MUST check a pointer argument for null.
--
Steve Clamage, stephen.clamage@eng.sun.com




Author: mikeq@primenet.com (Michael Quinlan)
Date: Sun, 19 Mar 1995 15:03:50 MST
Raw View
In article <3ki0bi$oqt@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:

>mikeq@primenet.com (Michael Quinlan) writes:

>>It is certainly possible to pass a NULL as a reference. Code fragment:

>>void yourfunc(int& r);
>>int* p = NULL;
>>yourfunc(*p);

>>I don't know if the behavior of this code fragment is defined by the
>>proposed standard.

>The behavior of this code is undefined. Any function taking a reference
>parameter is allowed to assume that the reference is real.

>The only way to try to make a "null reference" is to dereference a
>null pointer, the results of which are undefined. You have no
>business writing code which dereferences a pointer which could be null.

>(Please, no arguments about whether the compiler has to generate
>code to dereference 'p' above. Whether it must do so or not is
>an implementation detail, not part of the language definition.)

>If you prefer the belt-and-braces style of programming, you certainly
>can check your references for null if you want to.

>By contrast, a reliable program MUST check a pointer argument for null.

    I appreciate your response, and that of others, but to be honest, I am a
    bit troubled by this. Others have posted the part of the standard which
    says it that a reference cannot be NULL, but also says that no warning is
    required.

    That means that programmers are on the "honor system" to not use the
    sort of code listed above. Won't this almost certainly result in
    unreliable code? Programmers are human beings who will make mistakes
    even when they understand the details of the standard.

+---------------------------------+
| Michael Quinlan                 |
| mikeq@primenet.com              |
| http://www.primenet.com/~mikeq/ |
+---------------------------------+





Author: sfluhrer@ix.netcom.com (Scott Fluhrer)
Date: 20 Mar 1995 04:02:58 GMT
Raw View
In <3k9c3c$rpb@sndsu1.sedalia.sinet.slb.com> Besse Francois
<besse@clamart.wireline.slb.com> writes:

>
>
>class Matrix
>{
> Matrix(int, int, int, int);
> Matrix & operator=(const Matrix &);
> Matrix & operator+(const Matrix &);
               ^
>}

Gee, is this a good idea?  How would you implement Matrix::operator+?
If you say:

 Matrix& Matrix::operator+( const Matrix& a ) {
  Matrix Result;
  // Compute Result = a+b;
  return Result;
 }

you end up with a dangling reference.  On the other hand, if you say:

 Matrix& Matrix::operator+( const Matrix& a ) {
  // Add a to *this
  return *this;
 }

you don't have any problems with references to unallocated memory, but
you just broke how operator+ is supposed to work.  On the third hand, if
you say:

 Matrix& Matrix::operator+( const Matrix& a ) {
  Matrix* Result = new Matrix;
  // Compute *Result = a+b;
  return *Result;
 }

you now have a memory leak.  On the fourth hand, if you say:

 Matrix& Matrix::operator+( const Matrix& a ) {
  static Matrix Result;
  // Compute Result = a+b;
  return Result;
 }

You have a potential problem with expressions like:

 Matrix a, b, c;
 Matrix d = a + b + c;

Now, you could make it work with using a number of temporaries,
or (to be really ugly) using special object that has a conversion
operator to Matrix defined, and automatically deletes itself when
destructed (!), but, isn't that an awful lot of trouble to go through,
when returning an object works, and is (usually) not that expensive?

>     Francois
>---
>besse@clamart.wireline.slb.com
sfluhrer@netcom







Author: ccwup@$MAILHOST (WU Sheung Chau)
Date: 20 Mar 1995 08:21:04 GMT
Raw View
>>>>>Jason Merrill (jason@cygnus.com) wrote:
: Please justify your statement.  How is
: void f (char&);
: main () { f (*(char*)0); }
: different from
: main () { char &r = *(char*)0; }
: ?
: Jason
Sorry, I don't know what you want me to justfy.

Perhaps I have misinterpreted your last news.
So do you mean both code portions above will not pass the compiler?
i.e. do you mean the compiler will check the validity of the object
     being valid at the compilation, and give error?
or do you mean the language standard is set with some assertion, but whether
   it will be checked is compiler dependent?


However, my point is
 whether the object being refered is valid is usually
 cannot be determined during compilation.

The codes you quoted above may be simply enough for an INTELLIGENT
compiler to check it out. But it may fail for some programs:

e.g.
void f(char &);

main()
{
char *ptr;
int flag;

cin >> flag; // Indeed it is not a good way to get input
if (!flag) {
   ptr = (char *) flag; // essentially ptr = 0
   }
else {
   ptr = new char[10];
   }
f(*ptr); // whether *ptr is vaild is a run-time question!!

cin >> ptr; // Suppose we can input a pointer value ...
f(*ptr); // so, how about this one?
}


Here, I want to make myself clear.
I think the most INTELLIGENT compiler will not be able to say the
program above has an ERROR.
(However, I think the compiler (or lang. standard) should either give WARNING
to this; or
it does not allow program written in this way.
)

Actually, what I am disagreeing with you is that you quoted
 :- null references are prohibited and no diagnostic is required!!
  It seens that the compiler (or language definition itself) will do all
  checking and no diagnostic is required.

(What I think 'null references' in your reference material shall be the case of
declaring reference without initialization, except using as parameter
e.g.
int &i;
char &ch;
)

P.S. I am not an expert in C++. If I have misconception given here, pls.
forgive me and let me know. Sorry for such a long and boring reply.
After all, if what we are saying are two different things, or you cannot
get what I am saying (or vise versa), pls. just ignore this reply.




Author: jason@cygnus.com (Jason Merrill)
Date: 20 Mar 1995 09:14:58 GMT
Raw View
>>>>> WU Sheung Chau <ccwup@> writes:

>  whether the object being refered is valid is usually
>  cannot be determined during compilation.

Exactly.  And so the compiler is not required to diagnose null references,
even though they are invalid.

Jason




Author: pete@borland.com (Pete Becker)
Date: 20 Mar 1995 18:54:24 GMT
Raw View
In article <mikeq.170.002D3703@primenet.com>, mikeq@primenet.com (Michael Quinlan) says:
>
>    I appreciate your response, and that of others, but to be honest, I am a
>    bit troubled by this. Others have posted the part of the standard which
>    says it that a reference cannot be NULL, but also says that no warning is
>    required.
>
>    That means that programmers are on the "honor system" to not use the
>    sort of code listed above. Won't this almost certainly result in
>    unreliable code? Programmers are human beings who will make mistakes
>    even when they understand the details of the standard.
>

 Programmers are always on the "honor system". If you write a
function that can only be used with arguments that satisfy certain
constraints, calling the function with arguments that do not meet those
constraints is an error. Users of your function should not do that. It is
your responsibility to document what those constraints are, and it is
the responsibility of the user of your function to understand those
constraints and to abide by them.
 -- Pete




Author: thp@cs.ucr.edu (tom payne)
Date: 21 Mar 1995 01:01:50 GMT
Raw View
Michael Quinlan (mikeq@primenet.com) wrote:
: In article <ENNO.95Mar15220211@kitz.inferenzsysteme.informatik.th-darmstadt.de> enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner) writes:

: >The former guarantees that obj refers to an instance the latter not.
: >You're right that both sort of function-calls will place the address
: >of the stack (if the compiler uses pointer to implement references)
: >but calling with a reference-argument frees you i.e. from testing
: >whether 'o!=NULL'.

:     It is certainly possible to pass a NULL as a reference. Code fragment:

:     void yourfunc(int& r);

:     int* p = NULL;
:     yourfunc(*p);

:     I don't know if the behavior of this code fragment is defined by the
:     proposed standard.

:     Within yourfunc() you can test for NULL like this:

:     void yourfunc(int& r)
:     {
:         assert(&r != NULL);
:     }


If I understand correctly, one may think of a reference as a pointer
constant that is automatically dereferenced whenever it is used --
imagine an ninvisible * in front of it.  In the code above, a
reference to the pointer variable p is being passed, at a time when
the current value of p happens to be NULL.  Were it possible to see
the value of the reference itself (as opposed to its referent p), one
would find that its value is the address of p, which can never be
NULL.

Tom Payne




Author: enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner)
Date: 15 Mar 1995 21:02:11 GMT
Raw View
The former guarantees that obj refers to an instance the latter not.
You're right that both sort of function-calls will place the address
of the stack (if the compiler uses pointer to implement references)
but calling with a reference-argument frees you i.e. from testing
whether 'o!=NULL'.

        Enno

Mike Douklias <douklias@apcw.nfktech.com> writes:
>What is the difference between passing by reference (foo(obj &o)) and
>passing by pointer (foo(obg *o))?
>
>It will appear to me that in either case the address of the object
>instantiation will be placed on the stack.




Author: mikeq@primenet.com (Michael Quinlan)
Date: Thu, 16 Mar 1995 04:39:18 MST
Raw View
In article <ENNO.95Mar15220211@kitz.inferenzsysteme.informatik.th-darmstadt.de> enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner) writes:

>The former guarantees that obj refers to an instance the latter not.
>You're right that both sort of function-calls will place the address
>of the stack (if the compiler uses pointer to implement references)
>but calling with a reference-argument frees you i.e. from testing
>whether 'o!=NULL'.

    It is certainly possible to pass a NULL as a reference. Code fragment:

    void yourfunc(int& r);

    int* p = NULL;
    yourfunc(*p);

    I don't know if the behavior of this code fragment is defined by the
    proposed standard.

    Within yourfunc() you can test for NULL like this:

    void yourfunc(int& r)
    {
        assert(&r != NULL);
    }

+---------------------------------+
| Michael Quinlan                 |
| mikeq@primenet.com              |
| http://www.primenet.com/~mikeq/ |
+---------------------------------+





Author: Besse Francois <besse@clamart.wireline.slb.com>
Date: 16 Mar 1995 12:48:44 GMT
Raw View
There is also another convenience with reference for the
operator. With references, you can write

class Matrix
{
 Matrix(int, int, int, int);
 Matrix & operator=(const Matrix &);
 Matrix & operator+(const Matrix &);
}

main()
{
 Matrix a(1, 0, 0, 1);
 Matrix b(0, 1, 0, 1);

 // you can't write such an explicit line
 // without references
 Matrix c = a + b;
}

and c is Matrix(1, 1, 1, 1);

     Francois
---
besse@clamart.wireline.slb.com




Author: bkorb@admin.mport.com (Bruce Korb)
Date: Thu, 16 Mar 1995 19:36:36 GMT
Raw View
>Mike Douklias <douklias@apcw.nfktech.com> writes:
>>What is the difference between passing by reference (foo(obj &o)) and
>>passing by pointer (foo(obg *o))?
>>
>>It will appear to me that in either case the address of the object
>>instantiation will be placed on the stack.

enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner) wrote:

>The former guarantees that obj refers to an instance the latter not.
>You're right that both sort of function-calls will place the address
>of the stack (if the compiler uses pointer to implement references)
>but calling with a reference-argument frees you i.e. from testing
>whether 'o!=NULL'.

I believe you are ignoring the "foo( *ptr )" invocation, tho,
which *may* supply the NULL address.  One could argue that it is
a misuse because one *ought* to test a pointer for NULL before
dereferencing, but people ought to a lot of things...
--
Bruce Korb   | Microport, Inc.
bkorb@mport.com   | 108 Whispering Pines Dr.
(408) 438-8649   | Scotts Valley,  CA  95066




Author: jason@cygnus.com (Jason Merrill)
Date: 17 Mar 1995 02:44:57 GMT
Raw View
>>>>> Bruce Korb <bkorb@admin.mport.com> writes:

> I believe you are ignoring the "foo( *ptr )" invocation, tho,
> which *may* supply the NULL address.  One could argue that it is
> a misuse because one *ought* to test a pointer for NULL before
> dereferencing, but people ought to a lot of things...



Author: Ausen@disserv.stu.umn.edu ( Travis Ausen)
Date: Fri, 17 Mar 1995 05:45:15 GMT
Raw View
>
>         In fact the implementation of reference is a (constant) pointer.
The constant part is important since it means you can't change the
value of the pointer, only the value it references.




Author: janr@molienergy.bc.ca (Jan Reimers)
Date: Thu, 16 Mar 95 20:49:40 GMT
Raw View
In article <3k9c3c$rpb@sndsu1.sedalia.sinet.slb.com> Besse Francois <besse@clamart.wireline.slb.com> writes:
>There is also another convenience with reference for the
>operator. With references, you can write
>
>class Matrix
>{
> Matrix(int, int, int, int);
> Matrix & operator=(const Matrix &);
> Matrix & operator+(const Matrix &);
>}
>
>main()
>{
> Matrix a(1, 0, 0, 1);
> Matrix b(0, 1, 0, 1);
>
> // you can't write such an explicit line
> // without references
> Matrix c = a + b;
>}
>
>and c is Matrix(1, 1, 1, 1);

I don't understand any of this post.  operator+ will have to synthesize a new
object and should always return that object NOT a reference. As to the
statement "can't write .. without references", this makes no sence either.
You could pass every thing by value to operator= and operator+ and return
by value from operator+.  Passing by value is inefficient but allowed.
And why is c = Matrix(1,1,1,1), I can't think of any definition of these
int constructor arguments that results in (1,1,1,1).
I won't bother pointing out syntax errors.

--
 +--------------------------------------+-------------------------------------+
 | Jan N. Reimers,  Research Scientist  | Sorry, Don't have time to write the |
 | Moli Energy (1990) Ltd. B.C. Canada  | usual clever stuff in this spot.    |
 | janr@molienergy.bc.ca                |                                     |




Author: ccwup@$MAILHOST (WU Sheung Chau)
Date: 17 Mar 1995 08:03:55 GMT
Raw View
Jason Merrill (jason@cygnus.com) wrote:
: >>>>> Bruce Korb <bkorb@admin.mport.com> writes:

: > I believe you are ignoring the "foo( *ptr )" invocation, tho,
: > which *may* supply the NULL address.  One could argue that it is
: > a misuse because one *ought* to test a pointer for NULL before
: > dereferencing, but people ought to a lot of things...

: From the current WP:

:   8.3.2  References                                            [dcl.ref]

: 4         A reference  shall  be
:   initialized  to  refer  to a valid object or function.  In particular,
:   null references are prohibited; no diagnostic is required.

: Jason

I am afraid that the sentences quoted by Jason only applies to the case
of declaring a reference variable, like:

int value = 123;
int& ref = value;

Here, ref should be initialized to refer to a valid object.

However, for passing parameter by reference, the reference (formal) variable is
initialized to refer to the actual parameter when the function is called.
But whether the actual parameter is valid is usually only known in run-time. So
I don't think the complier will (or can) check it, and will result in a
run-time error.

You can check it by a small program:
-------------
#include <iostream.h>

void p2(char &);

void p2(char &pet)
{
   pet = 'A';
   cout << pet;
   return;
}

int main()
{
   char *peter;

   peter = NULL;
   p2(*peter);
   return 0;
}
-------------

Peter Wu
E8-P)
Email: ccwup@cityu.edu.hk




Author: Mike Douklias <douklias@apcw.nfktech.com>
Date: 14 Mar 1995 17:50:00 GMT
Raw View
What is the difference between passing by reference (foo(obj &o)) and
passing by pointer (foo(obg *o))?

It will appear to me that in either case the address of the object
instantiation will be placed on the stack.

Thanks
Mke Douklias.




Author: madhavi@india.ti.com (Madhavi)
Date: 15 Mar 1995 15:02:15 GMT
Raw View
In article <3k4l08$eni@pubxfer2.news.psi.net>, Mike Douklias <douklias@apcw.nfktech.com> says:
>
>
>What is the difference between passing by reference (foo(obj &o)) and
>passing by pointer (foo(obg *o))?
>
>It will appear to me that in either case the address of the object
>instantiation will be placed on the stack.

 You are right, the address of the object will be pushed onto
stack in either case. References are a syntactic convenience while
making function calls and also manipulating the arguments within
the function.

 ex., for a function foo that has to modify its arguments,
foo( xx ) is easier to use than foo ( &xx ). Similarly, referencing the
argument within foo doesn't require *xx notation when references are used.

 In fact the implementation of reference is a (constant) pointer.

 -Madhavi
 Texas Instruments (India) Limited.