2

I am reading through Stroustrup's 4th edition : The C++ Programming Language. I have a python/java background so the first 4 chapters are fine so far.

In Chapter 3 I saw:

complex& operator+=(complex z) { re+=z.re , im+=z.im; return ∗this; }

That began a day long attempt to write this question:

First I figured out that it is returning a reference to the object and not a copy. As I was able to confirm in this question.

And I was able to understand the difference between returning a reference into a reference variable vs. a regular variable from this question

And I did my own trial

class Test {
public:

    Test():x{5}{}

    int x;

    void setX(int a) {x = a;}

    Test& operator+=(Test z) {x+=z.x; return *this;}

    // the keyword this is a pointer
    Test* getTest() {return this;}

    // but I can return the reference by *this
    Test& getTest1() {return *this;}

    // or I can return a copy
    Test getTest2() {return *this;}

};

That lead me to question why it is called de-reference, so I did this trial

int x = 8;
int* p = &x;
int y = *p;
int& z = *p;

x++; // let's have some fun

std::cout << y << std::endl;
std::cout << z << std::endl;

As expected y = 8 and z = 9, so how did the de-reference return the address in one case, and the value in the other? More importantly how is C++ making that distinction?

Sam Hammamy
  • 10,819
  • 10
  • 56
  • 94

3 Answers3

3

It's exactly like in your Test class functions.

int y = *p;
int& z = *p;

y is a copy of what p points to. z is a reference to (not an address) what p points to. So changing z changes *p and vice-versa. But changing y has no effect on *p.

MFisherKDX
  • 2,840
  • 3
  • 14
  • 25
  • Thanks! That clarifies it a lot. But then if `z` is not an address, then what is it exactly? yes it's a `reference` to `x` but how is that represented? A symbolic link in linux stores the path to the target file – Sam Hammamy Nov 05 '17 at 21:13
  • References are their own type. The differences between references and pointers are subtle. A prominent difference is that pointers can be NULL and references can't. See this post for more detail. https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in – MFisherKDX Nov 05 '17 at 21:23
  • @MFisherKDX IIRC references are *supposed* to never be null but there are (albeit usually contrived) cases where they can be abused into referring to null values (or at least it was possible in one version of C++). – errantlinguist Nov 05 '17 at 21:37
1

It's possible to consider a pointer int* p as pointing to an address where data of type int resides. When you de-reference this, the system retrieves the value at that memory address (the address is the actual value of p itself). In the case of int y = *p; you put a copy of that int value on the stack as the locator value y.

On the other hand, de-referencing on the left-hand side in *p = 13; means you are replacing the int value *p stored at the memory address denoted by the value of p with the right-hand-side value 13.

The reference lvalue int& z in int& z = *p; is not a copy of the int value pointed to by p but rather a left-hand side reference to whatever is at the particular memory address returned by *p (i.e. the actual value held by p itself).

This doesn't mean much difference in your contrived case, but e.g. given a Foo class with a Foo::incrementCount() value,

Foo* p = new Foo();
p->incrementCount();

Foo& ref = *p;
ref.incrementCount();

The same method for the same instance will be called twice. In contrast, Foo foo = *p will actually copy the entire Foo instance, creating a separate copy on the stack. Thus, calling foo.incrementValue() won't affect the separate object still pointed to by p.

errantlinguist
  • 3,658
  • 4
  • 18
  • 41
1

As expected y = 8 and z = 9, so how did the de-reference return the address in one case, and the value in the other? More importantly how is C++ making that distinction?

The de-reference returned the actual thing referenced in both cases. So there is no distinction for C++ to make. The difference is in what was done with the result of the dereference.

If you do int j = <something>; then the result of the something is used to initialize j. Since j is an integer, the <something> must be an integer value.

If you do int &j = <something>; then the result of the something is still used to initialize j. But now, j is a reference to an integer, and the <something> must be an integer, not just an integer value.

So, what *this does is the same in both cases. How you use a value doesn't affect how that value is computed. But how you use it does affect what happens when you use it. And these two pieces of code use the dereferenced object differently. In one case, its value is taken. In the other case, a reference is bound to it.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Thanks David! So does this mean that I can do `int &j = some_function` : not the `return` but the `name of the function`? So that I can do `j()` later? – Sam Hammamy Nov 05 '17 at 21:31
  • @SamHammamy No, because a function is not a reference to an int. Since `j` is of type "reference to int", the thing on the right side of the `=` must be (or be convertible to) a reference to an integer, not a function. Also, a reference to an integer isn't callable. So `j()` doesn't make sense. – David Schwartz Nov 05 '17 at 22:25