On 21 Nov 2005 19:33:53 -0800, "Kaz Kylheku" <kkylheku@gmail.com>
wrote:
[color=blue]
>
>Bob Hairgrove wrote:[color=green]
>> On Mon, 21 Nov 2005 21:10:38 +0000 (UTC), Sven Hesse
>> <drmccoy@users.sourceforge.net> wrote:
>>[color=darkred]
>> >> I know how to use references but i DO not get WHY they exist other than
>> >> to add to the language. Are they actually needed for anything?
>> >
>> >Since they're basically pointers in disguise, they're not really
>> >needed, they just add some "beauty"/logical structure...[/color]
>>
>> No, they aren't pointers! This is just one more of those "urban myths"
>> which refuse to die.[/color]
>
>I'm not an idiot, nor perpetrator for myths, yet I will insist that
>they are.[/color]
You can insist anything you like, and so can I ... but that doesn't
really make a difference about how things really are. So let's have
some more fun here... ;)
[color=blue][color=green]
>> The C++ standard does not require a compiler to
>> allocate storage for a reference (section 9.3.2, paragraph 3).[/color]
>
>The C++ standard does not require a compiler to allocate storage for
>other things either. Integers, pointers, etc.[/color]
It does if I take the address of an object (instance) of one of these
types or otherwise use it in some meaningful way.
[color=blue][color=green]
>> Just
>> because some compilers implement references as pointers doesn't mean
>> that *all* compilers do it that way, or if they do it sometimes, they[/color]
>
>Name one compiler which doesn't implement a reference as a pointer,
>when that reference is returned from an external function, or when it's
>embedded in a struct or class.[/color]
This is the standard come-back: "Name one that doesn't!", and I am
tired of hearing it. I don't have time to disassemble the code
produced by the three or four compilers I regularly use in order to
see how this is done, and even if I did that for one function or
class, I couldn't be sure that the same compiler would always do it
the same way. Besides, as long as I can't use the reference any
differently than an object, I don't care -- more importantly, I don't
*have to* care. Fine with me if the assembly code shows that pointers
are used here. Why do YOU care so much, BTW?
As to reference members in a struct or class, I'd like to point out
that the standard disallows a pointer-to-member if that member has
reference type (hmm ... must be a good reason for that somewhere...).
[color=blue][color=green]
>> don't have to do that in every situation. And besides, we shouldn't
>> care how it is actually implemented. A compiler might reserve 1 MB of
>> storage for each reference for all we know, and it could still be a
>> "conforming implementation".[/color]
>
>It could also reserve that storage for a pointer and be a conforming
>implementation. So what?[/color]
Exactly. Or it could reserve 0 bytes instead. So what?
[color=blue]
>References are /semantically/ pointers. They are functionally
>indistinguishable from pointers.
>
>A reference can be converted to a pointer, and a pointer to a
>reference, without any loss of information.[/color]
Where do you get your strong guarantee that this statement is true?
The C++ standard supplies no such guarantee. As a matter of fact,
there is even a paragraph *warning* us that it is unspecified whether
or not storage is allocated for a reference. Why do you think that
sentence was deemed necessary by the standards committee? The standard
document is certainly thick enough already without meaningless text
thrown in.
[color=blue][color=green]
>> You cannot know either because sizeof()
>> with a reference returns the size of the object aliased, not of the
>> reference itself.[/color]
>
>Who cares? You do know that a reference can store a pointer, and that
>you can retrieve that original pointer from it. You also know that a
>reference will fetch the object for you that is pointed to. These
>properties are enough to identify it as being, operationally, a
>pointer.
>
>There is a recent thread about this; I'm not going to repeat all the
>arguments I made.[/color]
I'd like to see a link to it. No need to repeat anything.
[color=blue][color=green]
>> It also implies that compilers can take more liberty to optimize away
>> a reference and deal directly with the object for which it is an
>> alias.[/color]
>
>Compilers have exactly the same liberty as with a pointer. There is an
>extra piece of information that is statically know about a reference,
>without doing any analysis: that the pointer can't be reseated. The
>same thing can be known about a pointer, under similar circumstances.
>
>Moreover, a pointer can be const-qualified, so then it is statically
>attributed as unmodifiable.
>
> int x;
> int *p const = &x;
>
>Now, *p is an alias for x. Because p is const, we don't have to scan
>the scope for modifications to p, we can just assume that it always
>points to x. Right in the abstract syntax tree, we can replace *p
>occurences with x.
>
>If the address of p is taken and escapes into some nonlocal context
>then we have to allocate an object for it. Big deal.
>[color=green]
>> That's why it is not possible to take the address of a
>> reference,[/color]
>
>One reason that is not possible is that a reference isn't a type. So
>the resulting expression could not be mapped into the type system
>(other than as, say, a pointer-to-pointer).
>
>You could easily extend the language with a special address-of operator
>that gives you a pointer-to-pointer to the cell that holds the
>reference. Of course, the compiler would then have to ensure that there
>is something to point to.
>
>There is no unary && so it would fit the bill quite nicely.
>
> int &x;
> int **pref = &&x; // New! extra-strength address-of!
>
>I like it![/color]
I think it sucks, big time.
[color=blue]
>I say make it a pointer to a non-const pointer, so you
>could reseat the reference:
>
> *pref = &y; // I could use something like this from time to time!
>
>This feature could be added to C++ without semantically conflicting
>with anything.
>[color=green]
>> whereas a pointer will always occupy some bytes of storage
>> (unless it is optimized away).[/color]
>
>And a reference will always occupy some bytes of storage (unless it is
>optimized away).[/color]
How do you know? You are generalizing from specifics and have nothing
to back it up.
[color=blue]
>Everything occupies bytes of run-time storage unless it's optimized
>away.
>
>Where is the difference?
>
>A compiler can't blindly optimize away references. Only ones that are
>created under the right circumstances.
>[color=green]
>> Finally, it is the reason why there can
>> be no "null references".[/color]
>
>Yes there can. Dereference a null pointer and bind a reference to that
>lvalue:
>
> int &x = *(int *) 0;
>
>Is this well-defined or not? It doesn't matter. Because the answer to
>that question is a double-edged sword. If it's well-defined, it means
>you can have null references. If it's undefined, it's worse because you
>can still have null references by virtue of abusing the language
>implementation through undefined behavior.[/color]
Dereferencing a null pointer is always undefined behavior...the minute
it happens.
[color=blue]
>You can express the idea of creating a null reference, and C++
>compilers take it without complaint.
>
>Not only can there be null references, there can be invalid references.
>
>
> int &x = *p = new int;
> delete p; // x is now a dangling reference
>
>Consequently, references must be regarded with the same caution and
>respect as pointers. Since that's what they freaking are![/color]
It's not so. Dangling references can be a problem, but so can dangling
pointers, integer overflow, buffer overruns, floating-point rounding
errors, etc., etc. -- in short, just about any programming error you
can name. And it's much more common to encounter dangling pointers
than dangling references, and there is a reason for this.
If have a function which takes a reference argument, inside the scope
of the body of that function I can always assume that the reference is
valid. If it isn't, then the *caller* will get undefined behavior.
It's not the responsibility of the *callee* receiving the reference to
check its validity, it's the responsibility of the caller to provide a
valid reference. This is different with pointers. Because the
*language* doesn't prohibit passing a null pointer to a function as an
argument, I have to check *inside the function* whether I can use it
or not. This is not so with references. Anyone who wastes processor
cycles writing checks like the following is just plain silly:
void func(int& ri) {
if (&ri) {
ri = 4711;
}
else {
// naughty, naughty! ...
}
}
As to passing a dangling reference, I suppose there is always that
chance. But what are you going to do about it? What are you going to
do about dangling pointers? Is there any way that is safer than a
dangling reference?
--
Bob Hairgrove
NoSpamPlease@Home.com