Sometimes it just looks like C++ doesn't believe in C++. This is an excellent example. Well, actually this is. Whenever you're writing a non-static method, you can access the object being acted upon through this. this is a pointer to the object. It already comes initialised (because there's no other way of accessing the object, apart from using this), and you can't change its value. Such objects have a name in C++, but the name is "reference", not "pointer". So why isn't this a reference?

Let's go back to the favourite example of C++ textbooks: a complex numbers class. Ours will just have a "+" operation defined for it. For convenience, I'll just define operator+=(); it's easy to define operator+() using that (and the default copy constructor):

class Complex {
  double re, im;
public:
  Complex(double r, double i) : re(r), im(i) {}
  Complex& operator+=(const Complex& other) {
    re += other.re;
    im += other.im;
    return *this;
  }
}
This is almost the only way to use this; had this been Complex& instead of Complex* the only difference would have been return this;, which is surely clearer.

As it stands, this behaves like a reference, not like a pointer. It's not even like a constant pointer: that can be NULL (or 0, as we say in C++), but this is guaranteed to refer to a valid object. So why on earth isn't it a reference?

Because C++ doesn't believe in C++!

Perhaps Bjarne Stroustrup believed (believes?) that it would be common to set some other pointer equal to the this pointer. I could see where this would make sense in a linked list (say somewhere: head = this;). If this were a reference, you would have to take the address of it with the ampersand operator. Since references are declared with type&, taking the address of a reference just seems unnatural. People are quite accustomed to dereferencing pointers though.


Update: Mon Feb 12 2003

In light of the writeups by swmcd and DrPizza, I realize that my argument is not the reason that this was originally a pointer. However, I still believe it's a valid argument for why (in addition to backwards compatibility and other reasons) it remains a pointer. Taking the address of a reference is just contrary to the idea behind references. If I didn't think so, I would've requested this writeup be removed.

this's introduction into the language predates references -- it's a pointer because at the time it had to be, and it was never changed.

Changing it to a reference would be of little value:

  • Objects that manage their own lifetimes are not uncommon -- for instance, objects that delete this; when a reference count reaches zero -- this is particularly common in COM.
  • Assignment operator overloads (const T& operator=(const T&)) often check for self-assignment (that is, saying something such as:
    T a;
    a = a;
    
    ). Self-assignment rarely happens that obviously; it normally happens when variables are aliased. Now, one might naively think that the self-assignment test could look like:
    const T& operator=(const T& rhs)
    {
        if(*this == rhs)
        {
            return *this;
        }
    }
    
    but that has a problem. The minor problem is that some classes have no suitable operator==, so the test is impossible. The major problem is when rhs is actually a subclass of T rather than a T -- the equality test will do the wrong thing, as it will use T::operator==() rather than subclass::operator==(). The solution is to compare the addresses of this and rhs. If the addresses are identical, self-assignment is being attempted. If they're not, you can rest assured that they are different objects.
  • Many data structures (particularly node-based ones) use pointers to nodes, and they use this for this reason.

To summarize: this is not a reference because it predates references. It could have been changed into a reference, but the utility of this is questionable; many widely used constructs make use of its being an address. Making it a reference would save a little typing in some cases, but add a bit of typing in other cases -- there is no clear benefit.

Of course, if it really offends you so much you can always #define self (*this) and use self as you would otherwise use this.

Log in or register to write something here or to contact authors.