D pointers

Lars Knoll lars at trolltech.com
Thu Sep 29 12:49:08 BST 2005


On Thursday 29 September 2005 11:01, Dirk Mueller wrote:
> On Thursday 29 September 2005 10:06, Zack Rusin wrote:
> > the other way around. Lars can tell you more about his futile attempts
> > of optimizing this class (making it use lazy-parsing). Everything is
> > inlined so we couldn't do anything.
>
> So the issue wasn't the missing d pointer. Yes, the d pointer would have
> enforced to not write inline accessors, but other than that, inlined
> accessors are still faster than non-inlined ones.

And except for very few cases it doesn't matter that your access is not 
inlined. A typical GUI application is idle 99% of it's time. Things that have 
to be fast are mostly startup, painting and processing of large amounts of 
data.

Inline methods in an API severly limit the possibilities you later on have to 
change/refactor (and thus improve) your implementation.

We (as in the developers at Trolltech) have been bitten by this quite a few 
times during the lifetime of Qt3. This is one of the reasons we changed our 
policy for Qt4.

We moved everything into the d pointer for lots of reasons:

* We allocate a d pointer anyway. Even if you could avoid it in a 4.0 release 
by moving all members into the class itself you will most probably need the d 
pointer in a 4.1/4.2 release.
* You keep the public API clean and uncluttered. The header files remain very 
readable.
* You don't need to include thousands of header files; forward declarations 
are usually enough. This also reduces dependencies and compile time.
* Sometimes you use some variables in your class and you would like to replace 
them by something else in the next revision. You can only do that freely if 
the member is inside the d pointer.
* You can move all private methods into the d-pointer. Since private classes 
don't get exported you reduce the number of exported symbols which in turn 
reduces library size and startup time.


> > QUrl does create a Private and is
> > probably around 10x faster
>
> For different reasons. For example it doesn't do all those strange url
> reencodings KURL does.

The main problem was the KURL provided inline accessors to more or less all 
it's data. I wanted to make it faster at some point because the algorithm for 
visited links in KHTML used them (and was terribly slow). I had quite a few 
ideas how one could have done it, but none of them was possible _because_ all 
the accessors where inline. So I ended up using strings instead of KUrls in 
khtml for the task at hand.

If we stay with KURL as an example, what does it help you to have inline 
accessors for all data members, if construction of the object takes ages (and 
you can't fix it later). The positive effect of having these inline members 
was completely destroyed by the fact that we couldn't refactor the 
implementation to make it fast.

The main issue is usually that inlining looks like it makes things fast, but 
without measuring you do not know where your bottlenecks are. In most cases 
they are not the accessors for simple properties. But inlining might prevent 
future optimisations of your class. So in general I think one should not 
inline unless there is a _very_ good reason to do so.

Having method inline makes sense in one case: When you have a lowlevel class 
that you need to use in tight inner loops where you process lots of data. 
Basically container classes as QString, QList etc. But then you have to 
invest lots of resources to make sure you can live with the implementation 
for the lifetime of KDE4. But even then you usually put the data into a 
d-pointer to be able to use implicit sharing.

The good old rule that you shouldn't optimise without having measured also 
applies here. The gained flexibility by having the data structures hidden 
usually more than outweighs a loss of speed that is in most cases not even 
measurable.

Lars




More information about the kde-core-devel mailing list