REFERENCES REVEALED

J

JKop

I understand variables/objects and pointer variables perfectly:

int X = 5;

int* pX = &X;

*pX = 4;

int** ppX = &pX:

**ppX = 3;


---

I know exactly how references "behave", but I want to know how they actually
work!

For instance, take the following function:

void Repot(unsigned int* pX)
{
*pX = 45U;
}


The caller will do the following:

int main(void)
{
unsigned int X = 17U;

Repot(&X);
}


Obviously one could rewrite the above code as:


void Repot(unsigned int& X)
{
X = 45U;
}


int main(void)
{
unsigned int X = 17;

Repot(X);
}


But what I want to know is what's actually going on under the hood. One
quick little side note here though before I continue: When I first learned
about references, I detested them, I thought they were extremely stupid. One
may argue that they're easier to use, just as one may argue that an
automatic transmission car is easier to driver, but long story short, I
prefer manual transmission and detest references. So anyway, I could find no
justification for the introduction of references into C++, other than to
make operator overloading for classes possible. I was pleasantly amused when
I heard a quote from Bjarne himself stating that the reason he introduced
references into C++ was to enable operator overloading for classes. Fair
enough, and although in my opinion it is heavily contrived, it works! Just
for clarification, here's what I hate so much about references: Before, when
calling a function, you could specify "X" to indicate the value stored in
the variable, and you could specify "&X" to indicate the memory address of
the variable. With references, this is no longer so. (Yes, I am aware that
one can determine from the function prototype whether or not it's a
reference... I don't like it).

So anyway, how does the compiler deal with references? Does it simply treat
them as short-hand? Would the compiler turn my preceeding code (written
using references) back into pointers? ie. would it simply stick in the "*"
and "&" where appropriate? If the answer to this is Yes, then I pressume
that both samples of code would compile identically and hence allocate the
same amount of memory. (That is, the use of a reference does not supress the
need to have another variable within which to store the address of another
variable, ie. a pointer variable). If this is so, everything is fine and
dandy and I understand references, regardless of whether I like them. If
this is NOT so, I am at a loss! Before, I used to just think of it as
follows: If a function has a reference as a parameter, then you can think of
it as the scope of the variable being extended to the function which has
been called. This concept worked fine for me until I came across functions
whose return type was a reference. This is where my brain started
stuttering. Take the function prototype:

unsigned int& TeachFarmAnimals(void);

When you call the above function, what exactly are you getting back as a
return type?!! Are you simply receiving a pointer, and is the compiler just
sticking in the "*" and "&" for you where appropriate?


In summation:

Are references just pointers without the need to include "&" and "*", and is
the compiler just handling the "&" and "*" for you in the background?


-JKop
 
J

Jack Klein

I understand variables/objects and pointer variables perfectly:

int X = 5;

int* pX = &X;

*pX = 4;

int** ppX = &pX:

**ppX = 3;

They work very well, thank you.

[snip]
But what I want to know is what's actually going on under the hood.

Unfortunately, you are asking in the wrong place. The C++ standard
does not specify what goes on "under the hood". The standard defines
the interface to the programmer and the behavior when used correctly.
It places no requirements at all on the implementation as to how it
delivers the correct results. Nor is it necessary to for one to know
the details to write a correct C++ program.

If you want to understand how a specific compiler does these things,
study the object code it generates. If you want to discuss the
possible mechanisms in general, try
 
J

John Harrison

JKop said:
I understand variables/objects and pointer variables perfectly:

int X = 5;

int* pX = &X;

*pX = 4;

int** ppX = &pX:

**ppX = 3;


---

I know exactly how references "behave", but I want to know how they actually
work!

For instance, take the following function:

void Repot(unsigned int* pX)
{
*pX = 45U;
}


The caller will do the following:

int main(void)
{
unsigned int X = 17U;

Repot(&X);
}


Obviously one could rewrite the above code as:


void Repot(unsigned int& X)
{
X = 45U;
}


int main(void)
{
unsigned int X = 17;

Repot(X);
}


But what I want to know is what's actually going on under the hood. One
quick little side note here though before I continue: When I first learned
about references, I detested them, I thought they were extremely stupid. One
may argue that they're easier to use, just as one may argue that an
automatic transmission car is easier to driver, but long story short, I
prefer manual transmission and detest references. So anyway, I could find no
justification for the introduction of references into C++, other than to
make operator overloading for classes possible. I was pleasantly amused when
I heard a quote from Bjarne himself stating that the reason he introduced
references into C++ was to enable operator overloading for classes. Fair
enough, and although in my opinion it is heavily contrived, it works! Just
for clarification, here's what I hate so much about references: Before, when
calling a function, you could specify "X" to indicate the value stored in
the variable, and you could specify "&X" to indicate the memory address of
the variable. With references, this is no longer so. (Yes, I am aware that
one can determine from the function prototype whether or not it's a
reference... I don't like it).

You're missing out on two important aspect of references, one aesthetic, one
practical.

From the aesthetic point of view the chief difference between pointers and
references is that references always refer to the same object, unline
pointers. So if you need to refer to some object, and that reference (in the
general sense) is never going to refer to another object during its lifetime
you should consider using a reference (in the C++ sense) because it better
expresses what you are doing.

From the practical point of view there is the fact that a const reference
can bind to a temporary, something a pointer cannot do. Consider

class X;

void f1(const X*);
void f2(X);
void f3(const X&);
X g();

f1(&g()); // illegal

X t = g();
f1(&t); // ugly temp variable, extra copy

f2(g()); // extra copy, may or may not be optimised by compiler

f3(g()); // perfect

So anyway, how does the compiler deal with references? Does it simply treat
them as short-hand? Would the compiler turn my preceeding code (written
using references) back into pointers? ie. would it simply stick in the "*"
and "&" where appropriate?

Almost certainly, so certain am I that I've always assumed this to be the
case on every compiler I've ever used, and haven't actually bothered to
check. The only way to be sure would be to have a look at the machine code
your compiler generates.

john
 
J

JKop

I finally understand reference variables perfectly!! It's the way that they
were described to me that had me all confused. The books I've learned from
have never just stated plainly:

A reference variable is just a pointer variable.
A reference variable is just a pointer variable.
A reference variable is just a pointer variable.


It's like a const pointer variable, ie. you must initialize it upon
declaration:

int m = 5;

int* const pM = &m;

int& j = m;


Andt the second and final difference is that you treat it like a normal
variable, ie. you don't use the asterisk to access its data. And again, like
a normal variable, if you get the address of it, you get back an "int*", as
opposed to an "int**". It's so clear in my mind now. I fully understand:

Car& Porsche = *(new Car);

delete &Porsche;


and it's much more beautiful than:

Car* pPorsche = new Car;

delete pPorsche;


That is, you can work with a "Car", and not with a "Car*"!!


And similarly, when a function returns a reference:

int& GetApe(void);


It's returning a const pointer that you can treat as an "int" as opposed to
an "int*".


John Harrison, you said that an reference can also bind to a temporary, and
that's cool too, but just for clarity, so can a pointer. Consider the
following tested code:


long double Monkey(void)
{
return 87.343;
}

void Chocolate(long double* pTermite)
{
*pTermite = 56.242;

std::cout << *pTermite;
}

int main(void)
{
long double k;

Chocolate(&(k = Monkey()));



system("PAUSE");
return 0;
}



The temporary in the above is valid, right?


-JKop
 
J

JKop

JKop posted:
John Harrison, you said that an reference can also bind to a temporary,
and that's cool too, but just for clarity, so can a pointer. Consider
the following tested code:


long double Monkey(void)
{
return 87.343;
}

void Chocolate(long double* pTermite)
{
*pTermite = 56.242;

std::cout << *pTermite;
}

int main(void)
{
long double k;

Chocolate(&(k = Monkey()));



system("PAUSE");
return 0;
}



The temporary in the above is valid, right?


I TOTALLY dropped the ball there!! I'm making a copy of the temporary via:

k = Monkey();


Duh!!!


I see what you're getting at, John Harrison, that you simply can't get the
address of a temporary, ie:

&(Monkey())

The above doesn't compile. Yet, a reference *will* get the address!!


-JKop
 
O

osmium

JKop said:
I finally understand reference variables perfectly!! It's the way that they
were described to me that had me all confused. The books I've learned from
have never just stated plainly:

A reference variable is just a pointer variable.
A reference variable is just a pointer variable.
A reference variable is just a pointer variable.

What so you call a variable that can't be changed in your world?
 
J

JKop

osmium posted:
What so you call a variable that can't be changed in your world?

Ignoring your grammar...


I was given vague descriptions like so:


A reference is used so a function can edit the variable passed to it:

void Monkey(int& j)
{
j = 5;
}


It never actually just stated that a reference is just a const pointer
variable that's treated like a domestic non-pointer variable.

-JKop
 
K

Karl Heinz Buchegger

JKop said:
I finally understand reference variables perfectly!! It's the way that they
were described to me that had me all confused. The books I've learned from
have never just stated plainly:

A reference variable is just a pointer variable.
A reference variable is just a pointer variable.
A reference variable is just a pointer variable.

Wrong.
A reference is just another name for a variable.

Your compiler might use a pointer internally to represent it, but
it need not. Nevertheless the thinking model of a 'hidden pointer'
is a good one. But there is a difference between a mental model
and what things really are. References are alternative names.
 
K

Karl Heinz Buchegger

Karl said:
Wrong.
A reference is just another name for a variable.

Also wrong:

A reference is just another name for an object (it need not be a variable)
 
J

JKop

Karl Heinz Buchegger posted:
Wrong.
A reference is just another name for a variable.

Your compiler might use a pointer internally to represent it, but
it need not. Nevertheless the thinking model of a 'hidden pointer'
is a good one. But there is a difference between a mental model
and what things really are. References are alternative names.


struct Jeep
{
std::Vector& a;
std::Vector& b;
};


Then explain the above. If it's just another name for a variable, then what
the hell are a and b ?

Pointers is what they are, and on a 32-Bit Memory Model platform, sizeof
(Jeep) will be 64 Bits, which proves my point.


int main(void)
{
Vector j;
Vector k;

Jeep jeep = {j, k};
}
 
J

JKop

JKop posted:
Pointers is what they are, and on a 32-Bit Memory Model platform,
sizeof (Jeep) will be 64 Bits, which proves my point.


By which I mean:

struct Candy
{
long double& a;
long double& b;
long double& c;
};


The following statement will be true:


sizeof(Candy) == 3 * sizeof(void*);
 
J

Jeff Schwab

JKop said:
JKop posted:

No, it doesn't.
By which I mean:

struct Candy
{
long double& a;
long double& b;
long double& c;
};


The following statement will be true:


sizeof(Candy) == 3 * sizeof(void*);


Look, kid, you don't know half as much as you think you do. Stop
arguing with people who have more experience and a hell of a lot more
knowledge than you have.
 
J

Jorge Rivera

JKop said:
JKop posted:





By which I mean:

struct Candy
{
long double& a;
long double& b;
long double& c;
};


The following statement will be true:


sizeof(Candy) == 3 * sizeof(void*);

It might be true on whatever system you're compiling, but it is not true
in a general sense.

As well pointed out by other people, references are better thought of as
aliases.

By this I mean.

int a;
int &b = a;

Now you can modify either a or b, and you are affecting the same object.

Since a and b refer to the same object in the example above,
then &a == &b.

This leads to your notion of a "pointer variable".

However, please notice the difference. A pointer is a number that
represents a memory location. A reference is an object. It just refers
to an already existing object...

JLR
 
M

Mabden

A reference variable is just a pointer variable.
I think I have to agree. JKop!


This leads to your notion of a "pointer variable".

However, please notice the difference. A pointer is a number that
represents a memory location. A reference is an object. It just refers
to an already existing object...

And that is different to a "constant pointer variable" in what way...?
 
J

JKop

Jeff Schwab posted:
Look, kid, you don't know half as much as you think you do. Stop
arguing with people who have more experience and a hell of a lot more
knowledge than you have.


Fascist


-JKop
 
J

JKop

Jorge Rivera posted:
However, please notice the difference. A pointer is a number that
represents a memory location. A reference is an object. It just refers
to an already existing object...


int hedgehog = 4;


int* const pZebra = &hedgehog;
int& zebra = hedgehog;


*pZebra = 17;
zebra = 17;


void Sack(int*);


Sack( pZebra );
Sack( &zebra );


int porcupine = 8;

pZebra = &Porcupine; //ERROR, cannot assign to const variable

zebra = //Can't even try



-JKop
 
J

Jeff Schwab

Mabden said:
I think I have to agree. JKop!






And that is different to a "constant pointer variable" in what way...?

In that a reference isn't a variable at all.

A pointer is a variable in its own right. A reference is not. Pointers
have their own addresses in memory. If a compiler doesn't optimize
pointers away, they will exist at run-time.

A reference does not have its own address. Sometimes pointers are used
"behind the scenes" to implement reference semantics, as in the case
JKop mentioned of a struct containing references. These supporting
pointers are what take up the space JKop noticed. However, a reference
is primarily a new name used to refer to an existing variable (which may
or may not have a different name already).

I know this is subtle, so it's understandable if the difference still
isn't clear. Here's an example of a place where the differences between
"const pointers" and references mean that one can be used where the
other cannot:

int main ( )
{
typedef void* const Pointer_to_void;
typedef void& Reference_to_void;
}
 
J

Jorge Rivera

zebra = //Can't even try
Of couse not. References are initialized once, as dictated by the
standard, hence your compilers will whine endlessly...

Jorge L.
 
J

JKop

Jeff Schwab posted:
No, it doesn't.


class BankAccountInfoPointers
{
unsigned long int* const serial_number;
unsigned short int* const number_of_owners;
};


class BankAccountInfoReferences
{
unsigned long int& serial_number;
unsigned short int& number_of_owners;
};



Can anyone here suggest any reason at all why the following expression would
be false?:


sizeof(BankAccountInfoPointers) == sizeof(BankAccountInfoReferences)



This isn't an ignorant rhetorical question, I'm genuinely interested in a
possible reason, other than "'cause the Standard doesn't says it has to be".

-JKop
 
J

Jeff Schwab

JKop said:
Jeff Schwab posted:





class BankAccountInfoPointers
{
unsigned long int* const serial_number;
unsigned short int* const number_of_owners;
};


class BankAccountInfoReferences
{
unsigned long int& serial_number;
unsigned short int& number_of_owners;
};



Can anyone here suggest any reason at all why the following expression would
be false?:


sizeof(BankAccountInfoPointers) == sizeof(BankAccountInfoReferences)



This isn't an ignorant rhetorical question, I'm genuinely interested in a
possible reason, other than "'cause the Standard doesn't says it has to be".

No, who said the size of the structs would be different? The matching
size does not mean that references are the same as constant pointers,
though.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top