reading a declaration

D

Dave O'Hearn

Gary said:
You got me thinking; isn't a reference more like a #define that
has scope?
What I mean is: #define ref x
would do what int &ref = x;
does EXCEPT with define there is no scope or type checking. In
other words, whenever the compiler sees ref, it uses x.
If so, couldn't a compiler implement the references by precompiling
them with the substitution, adding #defines to set and unset the
variable and then compile as normally? This would be a lot of
overhead, of course, but would it give the same result?

It makes sense for objects that have names, but not all objects have
names. Like this,

int* ip = new int;
int& ir = *ip;
delete ip;

I think the "alias" view is counterintuitive on this. It makes sense to
say the reference declares a name for an object, but "alias" suggests
the object had a name to start with, which is not always the case. The
delete operation also shows that references can be invalid the same way
pointers can be, so a reference is just as likely to have a runtime
representation as a pointer is, even if technically that representation
is not considered "storage".

Another oddity is sizeof. sizeof(T&) is equivalent to sizeof(T). "Alias
without storage" suggests it would be invalid, while "like a pointer,
but" suggests it would be sizeof(T*). Neither explanation helps. sizeof
just has to be kept in mind as odd.
 
M

Mike Wahler

If a reference does not occupy storage, explain this:

#include <iostream>

struct A
{
int x;
};

struct B
{
B(int& i) : y(i) {}

int x;
int& y;
};

int main()
{
std::cout << "A: " << sizeof(A) << " B: " << sizeof(B) << '\n';
}

Output on my system:

A: 4 B: 8

That doesn't prove anything, except that perhaps internally the
reference's implementation adds some overhead. I'm talking about
references from a language perspective. E.g. you cannot find the
'sizeof()' a reference, take its address, etc.

-Mike
 
G

Gary Labowitz

Karl Heinz Buchegger said:
If the compiler sees what the reference refers to, yes there is some
similarity.
Actually I would guess this is what most compilers will do:
In the compiler internal table of variables mark each variable if it is a
reference. If it is, then this table also contains the name of the object
the reference stands for.

Whenever the compiler encounters a variable somewhere, it looks up that table
to see if it is a reference. If it is, the compiler checks if the object the
reference stands for is known to it. If it is, the compiler substitutes the
reference variable with the object the reference stands for and continues with
that instead of the reference.


ignoring all problems with #define right now, I think it would work in principle,
iff the compiler knows what the reference stands for. But it doesn't in all
cases :)

Yes, that's why I mention that there is a scoping problem, especially with
function calls. Just everybody be glad (especially me!) that I am not
writing a compiler.
 
R

Ron Natalie

Alan wrote:
C++ Reference
int x = 0;
int& ref = x;
ref is a reference to int, initialized with the int variable x.
You could substitute "which refers to" for "initialized with"
 
O

Old Wolf

msalters said:
void print( int const& x ) { // x refers to?
std::cout << x;
}

void foo() {
int i = 0;
print( i ); the x in print() will refer to i
int j = 1;
print( j ); the x in print() will refer to j
print( 3 ); the x in print() will refer to some constant 3
print( 3+1 ); the x in print() will refer to some temporary 4

I think '3' and '3+1' are in the same boat, they will
both create a temporary int to be bound to x.
If you remove the word 'const' above, then print(3) won't compile.
 
A

Alan

Alan said:
[snip]

To prove that a reference is
[snip]

Thanks to all for the discussion, I now have a much better
understanding of references vs. pointers and I acknowledge
that a reference really is an alias as this program illustrates.

#include <iostream>
using namespace std;

// Reference
int x = 0;
int& a = x;

int* const c = &a;
int* const d = &x;

int main() {

cout << "*c = " << *c << ", *d = " << *d << ", a = " << a << ", x = " << x << endl;
a++;
cout << "*c = " << *c << ", *d = " << *d << ", a = " << a << ", x = " << x << endl;
(*c)++;
cout << "*c = " << *c << ", *d = " << *d << ", a = " << a << ", x = " << x << endl;
(*d)++;
cout << "*c = " << *c << ", *d = " << *d << ", a = " << a << ", x = " << x << endl;
x++;
cout << "*c = " << *c << ", *d = " << *d << ", a = " << a << ", x = " << x << endl;

return 0;
}

Results:
*c = 0, *d = 0, a = 0, x = 0
*c = 1, *d = 1, a = 1, x = 1
*c = 2, *d = 2, a = 2, x = 2
*c = 3, *d = 3, a = 3, x = 3
*c = 4, *d = 4, a = 4, x = 4

Best wishes,
Alan
 
P

Paavo Helde

[...]
I didn't say it was. But try this: "A reference has identical syntax
and semantics to a pointer that is implicitly dereferenced, in all
operations except initialization." I believe this description is
flawless.

There is a special rule of prolonging the lifetime of a temporary when
bound to a const reference. I'm not sure if your "except initialization"
clause covers this or not. One certainly cannot exactly mimick this
semantics with pointers (without extra copying).

Another example is passing a temporary to a function expecting a non-
const reference parameter. This should be a compile-time error, but if
you replace the parameter with a pointer, you will get only a warning at
most about taking an address of a temporary.

So it seems that one can say safely: references behave exactly like
automatically dereferenced pointers... except in those cases where they
behave like references :)

Regards
Paavo
 
D

Dave O'Hearn

Paavo said:
There is a special rule of prolonging the lifetime of a temporary
when ound to a const reference. I'm not sure if your "except
initialization" clause covers this or not. One certainly cannot
exactly mimick this semantics with pointers (without extra copying).

Another example is passing a temporary to a function expecting a
non-const reference parameter. This should be a compile-time error,
but if you replace the parameter with a pointer, you will get only
a warning at most about taking an address of a temporary.

I think these both are related to initialization, since passing by
reference is a form of initializing a reference. The first really is
about the lifetime of the referred to object, not about the reference
itself. Still, they demonstrate that the "except initialization" bit I
threw in has extra excepts when it comes to temporaries.
 

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

Forum statistics

Threads
474,189
Messages
2,571,015
Members
47,616
Latest member
gijoji4272

Latest Threads

Top