Reputation: 13918
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
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
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