4

I'm learning C++ and pointers and I thought I understood pointers until I saw this.

On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.

Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.

How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.

For example here:

struct A {
  A& operator=(const A&) {
    cout << "A::operator=(const A&)" << endl;
    return *this;
  }
};
  • `this` is a pointer to the current object. So using the *pointer-to* operator `&` (like `&this`) would give us a pointer to the pointer to the object (in your case with the type `A**`). You need to use the dereference operator `*` to get the object itself. – Some programmer dude Feb 27 '22 at 16:32
  • `*this` dereferences the this pointer giving you the current object. Remember that `this` is a pointer not an object. The `&` has more than 1 meaning depending on the context. It can be either a reference or to return the address of. – drescherjm Feb 27 '22 at 16:33
  • Related: [https://stackoverflow.com/questions/35594378/address-of-operator-vs-reference-operator](https://stackoverflow.com/questions/35594378/address-of-operator-vs-reference-operator) – drescherjm Feb 27 '22 at 16:37

4 Answers4

3

this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.

According to the C++ 17 Standard (8.1.2 This)

1 The keyword this names a pointer to the object for which a non-static member function (12.2.2.1) is invoked or a non-static data member’s initializer (12.2) is evaluated.

Consider the following code snippet as an simplified example.

int x = 10;

int *this_x = &x;

Now to return a reference to the object you need to use the expression *this_x as for example

std::cout << *this_x << '\n';
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.

In C++, after a type name, it also means that what follows is a reference to an object of this type.

This means that is you enter :

int     a = 0;
int &   b = a;

b will become de facto an alias of a.

In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.

Obsidian
  • 3,719
  • 8
  • 17
  • 30
1

Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.

&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.

It would make more sense to ask why we don't do return this;.

The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:

int x = 42;
int *ptr = &x;
int &ref =  x;

So, similarly:

int *f1() return {return &x;}
int &f1() return {return  x;}
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
0

A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:

  • * converts a foo* to a foo&
  • & converts a foo& to a foo*

In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.

C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.

References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.

The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.

benrg
  • 1,395
  • 11
  • 13
  • *"no meaningful difference between `foo` and `foo&`"* Mhm, [expressions can't have reference types](http://eel.is/c++draft/expr#type-1). – HolyBlackCat Feb 27 '22 at 20:05
  • @HolyBlackCat Maybe you're agreeing with me, but if not: I think the paragraph you linked supports what I said. If `foo` and `foo&` were different, they would need to preserve the distinction in the further analysis. Since they aren't, they can simplify it by picking one notation, and they picked `foo`. – benrg Feb 27 '22 at 20:30
  • Yea, sorry if I wasn't clear, I'm agreeing with you. – HolyBlackCat Feb 27 '22 at 20:31