Dan Nissenbaum
Dan Nissenbaum

Reputation: 13918

Why is it "dumb to override the & operator and return *this*"?

Granted, I cannot think of any reason why I would ever want to override the unary & operator, but in https://stackoverflow.com/a/4542813/368896 the poster states, in regards to some class X:

...unless X does something really dumb, like overloading the unary & to return this

(NOTE: I assume this comment refers to the fact of the & operator returning this, not the fact of overriding the & operator itself.)

As I thought about that comment, it occurred to me that "returning this" is exactly what the & operator does - even in cases of multiple inheritance.

Given that one might never want to override the unary & operator, nonetheless why would it be dumb to have it return this (if you did decide to override it)?

Upvotes: 3

Views: 207

Answers (2)

Drew Dormann
Drew Dormann

Reputation: 63912

it occurred to me that "returning this" is exactly what the & operator does

You're right about that, although C++ also forbids taking the address of a temporary object.

In the context of the question you reference, which is about determining if an object is a temporary:

If you implement your own operator & that returns this, you will bypass this protection by telling the compiler that &(expression) is always valid. Consider:

struct foo
{
};

struct bar
{
    bar* operator&()
    {
        return this;
    }
};

template <typename T>
void test(const T*)
{
    // no temporaries, can't take address of temporary...right?
}

int main()
{
    foo x;
    test(&x); // okay, x is an lvalue

    /*
    test(&(foo())); // not okay, cannot take address of temporary
    */

    bar y;
    test(&y); // still okay, y is an lvalue

    test(&(bar())); // huh?! not taking address of temporary, calling operator&
}

Upvotes: 7

poitroae
poitroae

Reputation: 21377

It indeed has very limited uses. One usecase for example are smartpointers as they are often used in Direct3D to wrap IUnknown objects.

I assume you're not familiar with Direct3D, so I'll talk a bit more on that. Many Direct3D classes derive from IUnknown and after they've been used one must call Release. Yep, D3D internally uses reference counting. People tend to forget calling Release and it really is very tedious. So what one does is wrapping the IUnknown into a smartpointer which will do the release behind the scenes.

smart_pointer<ID3D11Device> device = // .. 

Thus, by stating &device you don't want the address of smart_pointer<ID3D11Device>, you want the address of ID3D11Device.

template <class T>
class com_ptr
{
private:
    T *inst;

public:
   // many other methods/overloadings

    T** operator & ()
    {
        return &inst;
    }
};

Bottom line: This way, you can invoke Release in the destructor and don't have to care about it in the rest of the code.

Bottom line 2: The better way to do it is to add a get() method which returns the intern object.

    T** get()
    {
        return &inst;
    }

Upvotes: 2

Related Questions