Oh God not references again...

F

Frederick Gotham

When I was a beginner in C++, I struggled with the idea of references.
Having learned how to use pointers first, I was hesitant to accept that
references just "do their job" and that's it.

Just recently, a poster posted looking for an explanation of references.

I'll give my own understanding if it's worth anything.

First of all, the C++ Standard is a very flexible thing. It gives a
mountain of freedom to implementations to do things however they like, just
so long as they achieve the objective. Consider virtual functions for
instance -- the Standard doesn't mention hidden pointers within objects or
V-tables, even though all implementations that I know of achieve the
behaviour of virtual functions by these means.

Let's start off with very simple code:

int main()
{
int i = 5;

int &r = i;

r = 7;
}

If someone is familiar with pointers, and also familiar with how computers
actually work (i.e. CPU instructions, registers, etc.), then they might
think that the code is treated as if it were written:

int main()
{
int i = 5;

int *const r = &i;

*r = 7;
}

Would this be a correct way of thinking about it? Yes, I suppose. Then
again, there are other ways of achieving the objective. For all you know,
the compiler might just look at the definition of "r" and think, "Hmm... r
is just i", and change it to:

int main()
{
int i = 5;

i = 7;
}

It might even achieve it internally something like:

int main()
{
int i = 5;

#define r i

r = 7;

#undef r
}

Who knows? All that matters is that the implementation accurately achieves
the behaviour of references.

References are most useful when passing objects, and returning objects,
from functions:

void Func(int &i)
{
i = 5;
}

How does the compiler compile this? Well, the C++ Standard doesn't say how.
In a way, I think of references as magical little things that just get the
job done.

However, as a person who's familiar with how computers actually work, I
know that there must be some sort of indirection involved (i.e. pointers)
if the function is not inline. Therefore, I would presume that the compiler
does it something like:

void __Func(int *const p)
{
*p = 5;
}

#define Func(i) __Func(&(i))

Then again, the compiler might have some new-fangled way of getting this
done, who knows?! All that's important is that the job gets done.

Also, with returning objects by reference:

int &Func()
{
static int i;

return i;
}

int main()
{
Func() = 7;
}

How does the compiler make this work? Well, if there's no function inlining
involved, then I'd presume it does something like:

int *Func()
{
static int i;

return &i;
}

int main()
{
*Func() = 7;
}

This would be one way for the compiler to achieve its objective. The fact
of the matter though is that references are little puffs of pixie dust.
They don't make sense, and they can't be explained. They just do what they
do.

References are special in one way though. When you initialise a reference
with an R-value, something special happens:

int &r = 5; /* Won't compile */

but:

int const &r = 5; /* No problem */

You might think this is strange -- how could it possibly work? How could it
be equivalent to something like:

int const *const p = &(5);

The answer is simple: It isn't. A "reference to const" is special if it is
initialised with an R-value. The original line, int &r = 5;, is treated as
if you wrote:

int const __literal = 5;
int const &r = __literal;

Now, you can see that the "temporary" object has the same lifetime as the
reference.

One more thing I'll mention before I go... someone was interested by the
following code:

struct MyStruct {
int &a;
double &b;
};

#include <ostream>
#include <iostream>

int main()
{
int i; double d;

MyStruct ms = {i,d};

ms.a = 5;

std::cout << sizeof ms << std::endl;
}

The person was interested as to why "ms" had a particular size. Answer: The
C++ Standard doesn't care. In reality though, the type, "MyStruct", must
achieve its objective. With a knowledge of how computers work, I can see
that the handiest way to achieve this particular objective would probably
be to use pointers internally:

struct MyStruct {
int *const a;
double *const b;
};

#include <ostream>
#include <iostream>

int main()
{
int i; double d;

MyStruct ms = {&i,&d};

*ms.a = 5;

std::cout << sizeof ms << std::endl;
}

This would be one way for the compiler to achieve the behaviour of
"MyStruct". But again, it doesn't have to do it this way.

References are magical pixie dust as the end of the day, they have no
foundation in actual computer science -- they just do what they do.
 
F

Frederick Gotham

Frederick Gotham:
The original line, int &r = 5;, is
treated as if you wrote:

int const __literal = 5;
int const &r = __literal;


Meant to write:

The original line, int const &r = 5;
 
K

kwikius

Frederick said:
When I was a beginner in C++, I struggled with the idea of references.
Having learned how to use pointers first, I was hesitant to accept that
references just "do their job" and that's it.

I think that like const references are partly a convention. When
passing (or returning) a reference you are saying there is an object
attached to this.. don't worry about it. When passing a pointer you are
saying you had better check there Is an object attached to this.

const is similar. It is of course possible in both cases to knacker the
convention if you feel the need to prove that its not infallible, there
is no law against it, but when you get down to it code that does what
it says on the tin is useful and used and code that doesnt aint.

regards
Andy Little
 
K

kwikius

kwikius said:
I think that like const references are partly a convention. When
passing (or returning) a reference you are saying there is an object
attached to this.. don't worry about it. When passing a pointer you are
saying you had better check there Is an object attached to this.

const is similar. It is of course possible in both cases to knacker the
convention if you feel the need to prove that its not infallible, there
is no law against it, but when you get down to it code that does what
it says on the tin is useful and used and code that doesnt aint.

Oh aye and compilers seem to do a better job optimising references and
inling functions than with pointers, maybe they just prefer ampersands
to asterisks...

regards
Andy Little
 
R

Roland Pibinger

I think that like const references are partly a convention. When
passing (or returning) a reference you are saying there is an object
attached to this.. don't worry about it. When passing a pointer you are
saying you had better check there Is an object attached to this.

I was told that references were introduced into C++ to support
operator overloading. IMO, a future version of C++ should unify
pointers and references.

Best wishes,
Roland Pibinger
 
Z

Zara

I was told that references were introduced into C++ to support
operator overloading. IMO, a future version of C++ should unify
pointers and references.

On, no please!

I love to use pointers with their feature of probably carrying a 0
(NULL) value, and I love to use references and their guarantee that
there really is an object hidden behind.

I also think unification would break massive amount of existing code.

Zara
 
K

kwikius

Roland said:
I was told that references were introduced into C++ to support
operator overloading. IMO, a future version of C++ should unify
pointers and references.

What? No...

(p?p->f():"");

regards
Andy Little
 
B

Bo Persson

Frederick said:
When I was a beginner in C++, I struggled with the idea of
references. Having learned how to use pointers first, I was
hesitant to accept that references just "do their job" and that's
it.

Why don't you post this in the "Should I learn C before C++" thread? :)

Unlearning is tough!

My first language was Simula, which had classes, references, and values. No
problem at all to see what a reference is, it is an alias for an object that
exists elsewhere.
Just recently, a poster posted looking for an explanation of
references.

I'll give my own understanding if it's worth anything.

First of all, the C++ Standard is a very flexible thing. It gives a
mountain of freedom to implementations to do things however they
like, just so long as they achieve the objective. Consider virtual
functions for instance -- the Standard doesn't mention hidden
pointers within objects or V-tables, even though all
implementations that I know of achieve the behaviour of virtual
functions by these means.

Let's start off with very simple code:

int main()
{
int i = 5;

int &r = i;

r = 7;
}
snip
Would this be a correct way of thinking about it? Yes, I suppose.
Then again, there are other ways of achieving the objective. For
all you know, the compiler might just look at the definition of "r"
and think, "Hmm... r is just i", and change it to:

int main()
{
int i = 5;

i = 7;
}

That's more like it. The reference r is another name for i.
References are most useful when passing objects, and returning
objects, from functions:

void Func(int &i)
{
i = 5;
}

How does the compiler compile this? Well, the C++ Standard doesn't
say how. In a way, I think of references as magical little things
that just get the job done.

In this case, the compiler could easily inline the function, and substitute
the actual parameter for i. Saves you all the trouble!
Also, with returning objects by reference:

int &Func()
{
static int i;

return i;
}

int main()
{
Func() = 7;
}

How does the compiler make this work? Well, if there's no function
inlining involved, then I'd presume it does something like:

int *Func()
{
static int i;

return &i;
}

int main()
{
*Func() = 7;
}

This would be one way for the compiler to achieve its objective.
The fact of the matter though is that references are little puffs
of pixie dust. They don't make sense, and they can't be explained.
They just do what they do.

Something like that, possibly. Func() is just another name for some int
variable.
References are special in one way though. When you initialise a
reference with an R-value, something special happens:

int &r = 5; /* Won't compile */

but:

int const &r = 5; /* No problem */

Non-const references to literals is not a good idea. Those who have tried
that in Fortran knows exactly why - it might let you change the value of the
literal.
References are magical pixie dust as the end of the day, they have
no foundation in actual computer science -- they just do what they
do.

And are much harder to abuse too. Just imagine how much better the world
would be without buggy pointer arithmetic!


Bo Persson
 
K

kwikius

Zara said:
On, no please!

I love to use pointers with their feature of probably carrying a 0
(NULL) value, and I love to use references and their guarantee that
there really is an object hidden behind.

Its probably best to beware that the guarantee can be broken, probably
unintentionally...


#include <iostream>

int & f(int & n)
{
int x= n;

int* px=0;

return *px;

}
int main()
{
int x=0;
f(x);

std::cout << "Seems ok but...time bomb...\n";

/*
one day...
*/
int y = f(x);

std::cout << "boink! y = " << y <<'\n';
}

regards
Andy Little
 
M

Mathias Gaunard

Frederick said:
When I was a beginner in C++, I struggled with the idea of references.
Having learned how to use pointers first, I was hesitant to accept that
references just "do their job" and that's it.

References and pointers are different things.

References reference another variable, acting as the real variable
itself. There are implicit conversions from a type to a reference to
that type and the other way around is handled by copy constructors. You
can also reference temporaries and literals even though they're not
named, if you make the type referenced const.
It's a really great concept that is the very base of copy semantics and
genericity.

Pointers are addresses. They hold a value, usually an integer, which
indicates a place in memory. That place in memory may contain the actual
type of the pointer, something else, or nothing.
The address 0 is by convention special and means there is nothing
pointed to.
You can use the * operator to get the actual pointed-to value.
Pointers is just a low-level tool on the machine level.

Both have in common implicit conversions to references/pointers to types
which are bases of the current types.

While references can be implemented with pointers, that doesn't mean
that references are just syntactic sugar over those.
They're a concept by themselves and have a specific goal.

Also, with returning objects by reference:

int &Func()
{
static int i;

return i;
}

>
int main()
{
Func() = 7;
}

How does the compiler make this work?

It won't make it work.
This is undefined behaviour.

You can't return a reference to a variable that doesn't exist anymore.
A nice compiler should have told you that.

References are magical pixie dust as the end of the day, they have no
foundation in actual computer science

What a reference is and what is its behaviour is are clearly defined. I
hardly see how it could have "no foundation".

Your problem seems to be that you're trying to know to whatever
instruction your compiler will convert your code to.
You shouldn't care at all (unless if after profiling you realize there
is a bottleneck somewhere due to the compiler not doing the right thing).
C++ is independent from any machine language or architecture anyway.
 
F

Frederick Gotham

Mathias Gaunard:

returning objects by reference:
It won't make it work.
This is undefined behaviour.

You can't return a reference to a variable that doesn't exist anymore.
A nice compiler should have told you that.


My compiler was even nicer:

Congratulations for making the variable in Func static!

It even bought me a bottle of champagne.

What a reference is and what is its behaviour is are clearly defined. I
hardly see how it could have "no foundation".


Because you can't touch, feel, smell, hear a reference. How do you pass a
reference to a function? It's a metaphysical concept. Pointers, on the
other hand, are solid; you can touch them, you can feel them.

Your problem seems to be that you're trying to know to whatever
instruction your compiler will convert your code to.
You shouldn't care at all (unless if after profiling you realize there
is a bottleneck somewhere due to the compiler not doing the right thing).
C++ is independent from any machine language or architecture anyway.


I'm not in with the crowd who leave optimisation to the last second. I
optimise as I go along.
 
A

Andre Kostur

Its probably best to beware that the guarantee can be broken, probably
unintentionally...

Not without invoking Undefined Behaviour....
#include <iostream>

int & f(int & n)
{
int x= n;

int* px=0;

return *px;

.... such as dereferencing a NULL pointer.
 
V

Victor Bazarov

kwikius said:
Zara said:
I love to use pointers with their feature of probably carrying a 0
(NULL) value, and I love to use references and their guarantee that
there really is an object hidden behind.

Its probably best to beware that the guarantee can be broken, probably
unintentionally...
[..dereferencing null pointer example..]

Undefined behaviour is just that. It doesn't actually have to involve
pointers at all. Just return a reference to a local object.

The whole point of that is the guarantee cannot be broken in a valid
program with defined behaviour. You simply cannot say what happens
in your example once you deref'ed that null pointer.

V
 
K

kwikius

Frederick said:
Mathias Gaunard:

returning objects by reference:


My compiler was even nicer:

Congratulations for making the variable in Func static!

It even bought me a bottle of champagne.




Because you can't touch, feel, smell, hear a reference. How do you pass a
reference to a function? It's a metaphysical concept. Pointers, on the
other hand, are solid; you can touch them, you can feel them.




I'm not in with the crowd who leave optimisation to the last second. I
optimise as I go along.

Unfortunately you are probably getting in the way of the compiler. A
reference is not a pointer. A pointer is an object holding the address
of a variable in memory, however a reference is just the address ( via
an offset relative to the stack pointer say), which the compiler
doesnt need to store in memory. In many cases the compiler can optimise
the pointer away so there isnt much difference but its easier in case
of the reference because there is no actual public object for the
programmer to mess about with. As the compiler deals with a reference
internally it can have more confidence re optimisation. Of course when
the programmer turns a pointer into a reference the compiler is stuffed
:)

regards
Andy Little
 
V

Victor Bazarov

kwikius said:
[..] A
reference is not a pointer. A pointer is an object holding the address
of a variable in memory, however a reference is just the address

How the hell did you come to that conclusion? Reference is NOT the
address.
( via
an offset relative to the stack pointer say), which the compiler
doesnt need to store in memory. [..]

<Sigh>... This is what happens when you try to explain matter through
mind or vice versa. Pointers are something *holding* the address, and
references *are* the address. So, pointers are holding references now?

V
 
K

kwikius

Victor said:
kwikius said:
Zara said:
I love to use pointers with their feature of probably carrying a 0
(NULL) value, and I love to use references and their guarantee that
there really is an object hidden behind.

Its probably best to beware that the guarantee can be broken, probably
unintentionally...
[..dereferencing null pointer example..]

Undefined behaviour is just that. It doesn't actually have to involve
pointers at all. Just return a reference to a local object.

The whole point of that is the guarantee cannot be broken in a valid
program with defined behaviour. You simply cannot say what happens
in your example once you deref'ed that null pointer.

Whatever.. I'll bet that somewhere, right now, some app is going AWOL
because of it ;-)

regards
Andy Little
 
K

kwikius

Victor said:
kwikius said:
[..] A
reference is not a pointer. A pointer is an object holding the address
of a variable in memory, however a reference is just the address

How the hell did you come to that conclusion?

By looking at reams of assembler output over the years?

Reference is NOT the

It aint magic. That for sure ;-)
( via
an offset relative to the stack pointer say), which the compiler
doesnt need to store in memory. [..]

<Sigh>... This is what happens when you try to explain matter through
mind or vice versa. Pointers are something *holding* the address, and
references *are* the address. So, pointers are holding references now?

I'm lost. Heres my original:

"> > [..] A
Now are you agreeing in that last paragraph or just being sarcastic?

Or maybe youre quibbling about the term address?

What I said seems good to me. I guess I'll just sit back and wait for
more sarcastic stuff now...


regards
Andy Little
 
R

Roland Pibinger

On, no please!
I love to use pointers with their feature of probably carrying a 0
(NULL) value, and I love to use references and their guarantee that
there really is an object hidden behind.

What I mean is that it makes no sense for a language to have 2 similar
constructs for (almost) the same underlying concept.
I also think unification would break massive amount of existing code.

Yes, but PHP5 also breaks PHP4 code. If you insist that a new language
version must be a superset of the current then no real evolution is
possible.

Best wishes,
Roland Pibinger
 
M

Mathias Gaunard

Frederick said:
My compiler was even nicer:

Congratulations for making the variable in Func static!

It even bought me a bottle of champagne.

Well, looks like I read this too quickly, didn't notice `i' was static.

Anyway, you've got quite a nice compiler. Did it use some kind of web
service to order the bottle?

Because you can't touch, feel, smell, hear a reference. How do you pass a
reference to a function? It's a metaphysical concept. Pointers, on the
other hand, are solid; you can touch them, you can feel them.

References and pointers are both equally defined by the C++ standard.
That pointers usually have very simple equivalents on the machine level
doesn't matter.

I'm not in with the crowd who leave optimisation to the last second. I
optimise as I go along.

There is a limit to optimization.
You should only optimize semantically or algorithmically as you code,
not think at the machine level.
Your compiler will probably outsmart you at this anyway, -O2 can
generate some assembler I don't even understand for simple cases.
 
V

Victor Bazarov

kwikius said:
[..pointers hold addresses, references are addresses..]
Now are you agreeing in that last paragraph or just being sarcastic?

Neither. References are not addresses. Nothing sarcasting about it.
You're trying to define an abstract concept with concrete content.
Don't. What's a class? Is it data or is it something that holds
data? Is it a set of functions or is it something that holds the
set of functions? References do not exist in run-time. Just like
classes. You can't compare pointers, which are objects, with other
element of the universe that isn't an object. Reference is like
a typedef. Are typedefs types or do they hold types? Neither.
Or maybe youre quibbling about the term address?
"Quibbling"?

What I said seems good to me. [..]

Whatever.

V
 

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,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top