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