references - how is it useful

C

codebloatation

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?
 
S

Sven Hesse

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...
 
M

Mike Wahler

Sven Hesse said:
Since they're basically pointers in disguise, they're not really
needed, they just add some "beauty"/logical structure...

It's not possible to overload operators without them.

-Mike
 
G

gottlobfrege

Sven said:
Since they're basically pointers in disguise, they're not really
needed, they just add some "beauty"/logical structure...


References are needed as a return type for operator =, so that x = y =
z works as expected, etc. There may be a few other places where they
are truly needed.

Everywhere else, in general, they are useful because you can't override
operators on the pointers, so using references keeps things as
'objects'. Of course, in most of those cases, you could dereference,
but yeah, it would get ugly.
 
S

Sven Hesse

References are needed as a return type for operator =, so that x = y =
z works as expected, etc. There may be a few other places where they
are truly needed.

Hmm, yeah, you're right, I haven't thought of operators, I should think
before answering next time... ^^;

(Though if the language were designed that way, you could do that with
pointer... *duck*)
but yeah, it would get ugly.

Agreed...
 
R

REH

Sven said:
Since they're basically pointers in disguise, they're not really
needed, they just add some "beauty"/logical structure...

How would you define an operator returning an lvalue without them?
 
K

KK

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?
In some cases it gives added security over pointers. For example, the
address of a pointer can be changed which can be avoided with
reference.
 
B

Bob Hairgrove

Since they're basically pointers in disguise, they're not really
needed, they just add some "beauty"/logical structure...

No, they aren't pointers! This is just one more of those "urban myths"
which refuse to die. The C++ standard does not require a compiler to
allocate storage for a reference (section 9.3.2, paragraph 3). 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
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". You cannot know either because sizeof()
with a reference returns the size of the object aliased, not of the
reference itself.

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. That's why it is not possible to take the address of a
reference, whereas a pointer will always occupy some bytes of storage
(unless it is optimized away). Finally, it is the reason why there can
be no "null references".

As others have already pointed out, there IS a real need for
references aside from what one can do with pointers.
 
K

Kaz Kylheku

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?

Their syntactic sugar plays a role in converting and copy constructors
and assignment operators.

A copy constructor in a referenc-free C++ could be defined using a
pointer:

SomeClass::SomeClass(const SomeClass *rhs) { /*...*/ }

But then, the address-of operator (unary &) would have to be used all
over the place.

SomeClass original;
SomeClass copy(&original);

You can't directly take the address of temporary objects:

extern SomeClass func();

SomeClass copy(&func()); // no can do

The following clumsy trick would do it:

class SomeClass { public: SomeClass *addr() { return this; } };

SomeClass copy(SomeClass().addr());

References aren't /necessary/ in some strict Turing sense in that
without them, certain things wouldn't be computable.

They are necessary to express certain semantics with certain syntax.

If you take it as a given that you want that syntax, then references
are necessary.

If you don't care for that area of expression, then they aren't
necessary, to you.
 
K

Kaz Kylheku

Bob said:
No, they aren't pointers! This is just one more of those "urban myths"
which refuse to die.

I'm not an idiot, nor perpetrator for myths, yet I will insist that
they are.
The C++ standard does not require a compiler to
allocate storage for a reference (section 9.3.2, paragraph 3).

The C++ standard does not require a compiler to allocate storage for
other things either. Integers, pointers, etc.
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

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.
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".

It could also reserve that storage for a pointer and be a conforming
implementation. So what?

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.
You cannot know either because sizeof()
with a reference returns the size of the object aliased, not of the
reference itself.

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.
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.

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.
That's why it is not possible to take the address of a
reference,

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! 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.
whereas a pointer will always occupy some bytes of storage
(unless it is optimized away).

And a reference will always occupy some bytes of storage (unless it is
optimized away).

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.
Finally, it is the reason why there can
be no "null references".

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.

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!
 
B

Bob Hairgrove

I'm not an idiot, nor perpetrator for myths, yet I will insist that
they are.

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... ;)
The C++ standard does not require a compiler to allocate storage for
other things either. Integers, pointers, etc.

It does if I take the address of an object (instance) of one of these
types or otherwise use it in some meaningful way.
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.

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...).
It could also reserve that storage for a pointer and be a conforming
implementation. So what?

Exactly. Or it could reserve 0 bytes instead. So what?
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.

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.
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.

I'd like to see a link to it. No need to repeat anything.
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.


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!

I think it sucks, big time.
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.


And a reference will always occupy some bytes of storage (unless it is
optimized away).

How do you know? You are generalizing from specifics and have nothing
to back it up.
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.


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.

Dereferencing a null pointer is always undefined behavior...the minute
it happens.
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!

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?
 
N

Neil Cerutti

I'm not an idiot, nor perpetrator for myths, yet I will insist
that they are.

You seem to be confused between an "is a" relationship and an "is
implemented in terms of" relationship.
 
K

Kaz Kylheku

Bob said:
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... ;)


It does if I take the address of an object (instance) of one of these
types or otherwise use it in some meaningful way.

If conditions are such and such, then something has to be done to make
the semantics work. No kidding!

References also become real storage objects under some circumstances.
Their address can be taken implicitly. If a struct or class contains a
reference, and I have a pointer to an instance of that struct or class,
then, indirectly, I have an address of that reference, (modulo some
displacement that may be zero).

So, references sometimes exist in the run-time environment as storage
objects in memory, and sometimes they disappear in the translation.

Exactly the same thing can be said about other kinds of values.
Fine with me if the assembly code shows that pointers
are used here. Why do YOU care so much, BTW?

Because I disagree with the blatant misinformation being pushed around
that references are not pointers. They aren't pointers in the type
system, but they are operationally equivalent to pointers and they are
real run-time objects except when optimized away.
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...).

It also disallows a regular pointer! If you take the address, you get
the target object.

Of course there is a good reason! References are not represented in the
type system.

There is no way you can even syntatically express pointer-to-reference
or pointer-to-member-reference. The type construction syntax isn't
valid.

But the reference is there in that object.

You also can't make pointers to bitfields. That doesn't mean they
aren't storage.
Exactly. Or it could reserve 0 bytes instead. So what?

It could not reserve zero bytes if the object cannot be optimized away.
If storage is needed for the reference, then it has to be large enough
to hold all the same information as a pointer.
Where do you get your strong guarantee that this statement is true?

In the perfectly well-formed, conforming code I can write to
demonstrate it.

extern int &ptr_to_ref(int *);
extern int *ref_to_ptr(int &);

int a = 42;
int *b = ref_to_ptr(a);
int &c = ptr_to_ref(b);
int *d = ref_to_ptr(c);
int &e = ptr_to_ref(d);

Now b, c, d and e all refer to a. Their initializing values were
smuggled through external functions, which can be trivially defined
like this:

int &ptr_to_ref(int *ptr) { return *ptr; }
int *ref_to_ptr(int &ref) { return &ref; }
The C++ standard supplies no such guarantee.

The C++ doesn't make guarantees; vendors do.

The C++ standard does require the above conversions to work.

It shows that we can freely convert between a pointer and a reference,
and that we can do this through an external data pathway: a blackbox
where we pass in a reference and get a pointer back or vice versa.

The only sticking point is that a null pointer can't be smuggled
through this conversion system because of the null dereference problem.
So there is one value that references don't have in their domain
compared to pointers. In practice, you can coax null references out of
your compiler. It's quite portable and harmless.
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.

I have found it, it: "It is unspecified whether or not a reference
requires storage."

"Unspecified" is a normative term. It means that a choice must be made
among alternative requirements, without any documentation!
Why do you think that
sentence was deemed necessary by the standards committee?

That sentence says absolutely nothing.

It says that a choice must be made between among a set of alternatives
which exhaustively partition the space of all possibilities.

The same requirement (or absence of requirement) can be made simply by
omitting such a sentence.

If you erase the sentence, the implementor must still decide whether or
not a reference requires storage. And the implementor is still free not
to document anything about that choice.

The only situations when it's useful to explicitly say that something
is unspecified, rather than leave a lack of specification, is when it
might be mistakenly assumed that the behavior is specified, with dire
consequences.

A good example of this is the evaluation of function arguments. The
order is unspecified. If that isn't spelled out, implementors, or more
likely users of the language, might mistakenly assume that the order is
left to right.

It's very easy to write code which depends on that order of evaluation.
That code doesn't even have to invoke undefined behavior. For instance:

x(f(), g(), h());

results in the functions f, g and h being called in one of six possible
orders, each possibility being well-defined behavior.

So in other words, the behavior of a correct program can differ because
of this unspecified behavior. A correct test case can be written which
reports which way the choice went.

To write code that depends on whether or not a reference has storage,
you'd have to write some dubious construct, whose behavior is undefined
regardless of whether or not references have storage.

So it's not useful to spell this out at all.
How do you know? You are generalizing from specifics and have nothing
to back it up.

How do I know? Namely that the sentence I have written covers the
entire space of logical possibilities.

Either the object occupies run-time storage, or it doesn't.

P or not P

Always true!
 
N

Niklas Norrthon

Sven Hesse said:
Hmm, yeah, you're right, I haven't thought of operators, I should think
before answering next time... ^^;

(Though if the language were designed that way, you could do that with
pointer... *duck*)

If the language were designed in a slightly different way we would
have APL instead of C++...

/Niklas Norrthon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top