2

I have read some of the technical differences between references and memory addresses here, however I am trying to find a more abstract way to understand them. Consider the code:

char foo = 'a';
char& bar = foo;
char& bar2 = *(char*)(&foo);
cout << bar << endl;
cout << bar2 << endl;

The output in both cases is 'a'. Is it then correct to conclude from this that a reference (bar2) is simply a memory address (&foo) with an associated type (char)? Or does this explanation fall apart?

Community
  • 1
  • 1
Dan Brenner
  • 880
  • 10
  • 23
  • 1
    `*(char*)(&foo)`: This is the same as `foo`. – David G Jul 22 '14 at 21:41
  • Do you mean pointers and references? – Deduplicator Jul 22 '14 at 21:43
  • 1
    Once you understand that `char foo; char &bar = foo;` and `char bar; char &foo = bar;` are exactly identical , you will understand what references are :) (well, lvalue references anyway). – M.M Jul 22 '14 at 21:52
  • In C++ you can pass an Object by reference or by value. When you use a pointer in C++ such as: int *x = 100; x is a variable that points to a memory address/location eg: 650, where it points to the value 100. Where as: int &y = x; y is a variable that makes a reference to the value of x, it also points to the same memory address 650. Now if you change the value of x say: x = 450; then you have also change the value of y. y is just a reference to x in this case and memory address is 650. In C++ "&" or a reference to, is mostly used with input parameters such as constructor and functions. – Juniar Jul 23 '14 at 02:33

3 Answers3

5

The most succinct definition of a reference in C++ is that:

It declares a named variable as a reference, that is, an alias to an already-existing object or function.

  1. Its value is the same as the object it is an alias of.
  2. Its address (obtained by the & operator) is the same as the address of the object it is an alias of.
R Sahu
  • 204,454
  • 14
  • 159
  • 270
3

Any time you have a value (i.e. an object that is the result of evaluating an expression) in C++, you can bind that value to a reference variable. Evaluating the reference later results in an lvalue that is precisely the object which was bound to the reference. For example:

int a = 10;
a;             // the value of the expression is immediately discarded
int & r = a;   // this time the value is bound to a reference variable
r;             // this is the same value as a
r = 20;

Evaluating both a and r produces an lvalue of type int, which is the variable a.

Another example:

Foo f();

f();            // a discarded prvalue of type Foo
Foo && r = f(); // this time the value of f() is bound to r
r.do_stuff();

This time, each evaluation of f() produces a distinct value of type Foo (a "temporary object"). The first one is immediately discarded; the second one is bound to the reference r. Evaluating r produces an lvalue of type Foo, namely the temporary object returned from the second function call.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    This seems to disagree with the distinction between *object* and *value*, where an *object* stores or contains a *value*. – dyp Jul 22 '14 at 21:54
  • @dyp: I think that got clarified in C++14, which uses the term "temporary object" consistently. So once you bind a value to a reference, you can observe the object. – Kerrek SB Jul 22 '14 at 22:01
  • I know that there's been a defect report (which I cannot find unfortunately) about "temporary" vs "temporary object", but I'm unaware of any such dramatic change in terminology. An object can contain a value; you can change the value it contains. I do not think that binding a value to a reference makes much sense, especially since you can modify something bound to a non-const ref. As far as I know, you always bind an object to a reference, that object might be constructed *from* a value. – dyp Jul 22 '14 at 22:07
  • This answer feels either wrong or confusing. If *value* is in fact the right term from the standard than I think that needs some explaining. To me value is something like 10. So It sounds like you're saying 10 is bound to `r` which is clearly wrong. – PeterSW Jul 22 '14 at 22:10
  • Oh great. The Standard and even the latest github draft is inconsistent :( [dcl.init.ref]/1 seems to disallow initializing a reference from a value, it requires an object or function. Later it uses "value of the initializer expression", which sounds odd as well. – dyp Jul 22 '14 at 22:17
  • Found the DR/resolution: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3918.html – dyp Jul 22 '14 at 22:20
  • @dyp: Yep, indeed :-) – Kerrek SB Jul 22 '14 at 23:29
  • @PeterSW: `10` is a literal. Evaluating a literal produces a suitable prvalue, and *that* value is bound to the reference when you say `int && r = 10;`. Maybe you are thinking of "value" in the sense of "equivalence class of objects that compare equal". – Kerrek SB Jul 22 '14 at 23:48
  • The Standard contains such confusing statements as "The value of a literal such as `12`, `7.3e5` or `true` is also a prvalue." (which suggests that a value is an expression) Anyway, for `int && r = 10;`, the bullet point [dcl.init.ref]/5.2.2.2 applies (yay numbered bullet points!) which says that *a temporary is created* which is copy-initialized from the initializer expression. So the *value* is not bound directly. (I think it should be *a temporary object*, btw) – dyp Jul 23 '14 at 00:18
  • @dyp: I'm using the word "value" in the sense of "value of an expression", which can be, say, an lvalue, which *is* the object. In that sense to different integer variables may be equal but are distinct values, in the sense that they can be separately addressed and modified. I agree though that the terminology is confusing. – Kerrek SB Jul 23 '14 at 00:25
  • @PeterSW: I reworded it a bit. The terminology is confusing, agreed. I use "value" in the sense of the value categories, i.e. things produced by evaluating expressions. – Kerrek SB Jul 23 '14 at 00:29
2

bar2 is identical to bar, since *(char*)(&foo) (value at the address of foo, interpreted as char) is the same as foo itself.

The important thing to understand here, is that a reference is basically a pointer that is automatically dereferenced, and whose address cannot be changed. Or, in other words, an alias for a variable or memory location.

Consider this:

char *c = new char('x');
char &ref = *c;
ref = 'y';
assert(*c == 'y'); //the memory at c was changed through ref
assert(&ref == c); //the address of ref is the same as c, because ref is an alias for the memory at c

char c2 = 'x';
char &ref2 = c2;
char *p = &c2;
c2 = 'y';
assert(p == &ref2);
assert(ref2 == 'y' && *p == 'y');
axnsan
  • 888
  • 10
  • 16