While I investigate source code of Qt I saw that trolltech guys explicitly use this keyword to access a field on destructor.
inline ~QScopedPointer()
{
T *oldD = this->d;
Cleanup::cleanup(oldD);
this->d = 0;
}
So, what's the point of this usage? Are there any benefits?
Edit: For those who vote for closing this question, I suspect that this usage is for some class inheritance cases
A part of QScopedPointer class definition:
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer
C++ answer (general answer)
Consider a template class
Derivedwith a template base class:thishas typeDerived<T>, a type which depends onT. Sothishas a dependent type. Sothis->dmakesda dependent name. Dependent names are looked-up in the context of the template definition as non-dependent names and in the context of instantiation.Without
this->, the namedwould only be looked-up as a non-dependent name, and not be found.Another solution is to declare
din the template definition itself:Qanswer (specific answer)
dis a member ofQScopedPointer. It isn't an inherited member.this->is not necessary here.OTOH,
QScopedArrayPointeris a template class anddis an inherited member of a template base class:so
this->is necessary here:It's easy to see that it's easier to just put
this->everywhere.Understand the reason
I guess it isn't clear to all C++ users why names are looked-up in non-dependent base classes but not in dependent base classes:
There is a reason beside "the standard says so": cause of way name binding in templates works.
Templates can have name that are bound late, when the template is instantiated: for example
finf (this). At the point ofDerived2::f()definition, there is no variable, function or type namefknown by the compiler. The set of known entities thatfcould refer to is empty at this point. This isn't a problem because the compiler knows it will lookupflater as a function name, or a template function name.OTOH, the compiler doesn't know what to do with
d; it isn't a (called) function name. There is no way to do late binding on non-(called) functions names.Now, all of this may seem like elementary knowledge of compile-time template polymorphism. The real question seems to be: why isn't
dbound toBase<T>::dat template definition time?The real issue is that there is no
Base<T>::dat template definition time, because there is no complete typeBase<T>at that time:Base<T>is declared, but not defined! You may ask: what about this:it looks like the definition of a complete type!
Actually, until instantiation, it looks more like:
to the compiler. A name cannot be looked-up in a class template! But only in a template specialisation (instantiation). The template is a factory to make template specialisation, a template isn't a set of template specialisation. The compiler can lookup
dinBase<T>for any particular typeT, but it cannot lookupdin the class templateBase. Until a typeTis determined,Base<T>::dremains the abstractBase<T>::d; only when typeTis known,Base<T>::dstart to refer to a variable of typeint.The consequence of this is that the class template
Derived2has a complete base classBase0but an incomplete (forward declared) base classBase. Only for a known typeT, the "template class" (specialisations of a class template)Derived2<T>has a complete base classes, just like any normal class.You now see that:
is actually a base class specification template (a factory to make base class specifications) that follows different rules from a base class specification inside a template.
Remark: The reader may have noticed that I have made-up a few phrases at the end of the explanation.
This is very different: here
dis a qualified name inDerived<T>, andDerived<T>is dependent sinceTis a template parameter. A qualified name can be late-bound even if it isn't a (called) function name.Yet another solution is:
This is equivalent.
If you think that inside the definition of
Derived<T>, the treatment ofDerived<T>as a known complete class sometimes and as an unknown class some other times in inconsistent, well, you are right.