[Development] Question about QCoreApplicationData::*_libpaths

Marc Mutz marc.mutz at kdab.com
Thu Jan 21 11:03:08 CET 2016


On Thursday 21 January 2016 07:59:18 Mathias Hasselmann wrote:
> Am 21.01.2016 um 08:00 schrieb Marc Mutz:
> > On Thursday 21 January 2016 05:24:35 Kevin Kofler wrote:
> >> Marc Mutz wrote:
> >>> On Wednesday 20 January 2016 22:50:43 Kevin Kofler wrote:
> >>>> All these are horrible and error-prone hacks that have obvious
> >>>> lifetime issues. You are complaining about Qt containers because the
> >>>> detaching can invalidate iterators. Well, the lifetime issues you
> >>>> introduce with the above proposed solutions are much worse! And a
> >>>> caching mutable member also destroys thread-safety (in addition to
> >>>> the obvious lifetime issue that the next call surprisingly
> >>>> invalidates your existing reference).
> >>> 
> >>> One word: QModelIndex.
> 
> Sorry Marc, no. Really.
> 
> QModelIndex is entirely unrelated to the problem Eike raised.

I was replying to Kevin. QModelIndex exactly fits his complaints about const-&:

It's a reference used in interfaces. As soon as you store it, though, it may 
become stale at the next opportunity (like when calling a virtual function). 
You're supposed to store them in QPersistentModelIndex in that case. But QPMI 
is extremely expensive.

Compare that to:

     const std::vector<QFoo> & foos();

You can either assign the result to a const-& (=QModelIndex case), get max 
performance, but suffer from possible invalidation if you call out to unknown 
code. Or you store it in a copy, incurring the copy, but insulating yourself 
from changes to the original object (=QPersistentModelIndex case).

They really are two instances of the same class of problem: dangling 
references. And you cannot escape that problem. Not in C++, and not in other 
imperative languages, either. If you replaced QMI with an int, as you could, 
for QAbstractListModels, then you'd have exactly the same problems of 
invalidation (who updates your int if the row it points to gets removed?).

> I highly reward your expertise and what you are doing for Qt, and I
> really don't want my high opinion of you being spoiled. So please grab
> fine cup of tea, take a comfortable seat and spent some time on
> understanding, why this discussion took such dramatic shift away from
> its initial topic, why you are receiving such heat. Also please take
> some time to recall what other properties but performance are important
> when designing general purpose libraries.

If I have given the impression that it's just about speed, I'm sorry.

Speed is one argument, yes. If the Qt class had that much more (useful, to 
avoid counting indexOf() as a feature) features than the std counterpart, I 
would be the last to talk about replacing it. QString e.g. has superior 
Unicode handling. We can discuss how it should be laid out (CoW or not, say), 
but no-one challenges the very right of QString to exist.

But if a Qt class has only half the feature of its std counterpart and at the 
same time performs worse, then the question needs to be asked whether that 
class really needs to be in Qt.

So yes, I cannot shake the deeply-ingrained C++ principle of "don't pay for 
what you don't use". It's what keeps C++ relevant these days, despite its 
rough edges.

But speed is not the only reason:

I don't like Q_FOREACH not just because it performs badly, which it really 
doesn't, usually, for Qt types, but because it makes it hard to reason about 
the code (why is a copy taken? Is is needed?).

I don't like QThread being a QObject because it makes misusing the API all too 
easy.

I don't like QList because only experts can tell which guarantees it provides 
for any given type (can I keep references into the container across appends?). 
It's also the only container in the C++ world where iterator and reference 
validity are not synonyms: An append where capacity() == size() invalidates 
iterators in both QList modes, but only invalidates references in vector-with-
padding mode.

I don't like CoW because it creates long-range effects that are also the 
underlying reason we don't like global variables. It also makes any complexity 
specifications moot, because you never know whether you will incur that extra 
O(N) detach.

I don't like QSharedPointer because it does nothing better, and lot of things 
worse, than shared_ptr and was only added (long after boost::shared_ptr and 
tr1::shared_ptr came into existence) because of an overly strict sense of BC 
that extends beyond the Qt libraries (aka "we can't use boost/std in our 
APIs").

As for why I am receiving such heat: I don't. It's the same couple of persons 
every time that troll around. I should get better at not feeding them, sure.

The people that matter in Qt development, however, take this constructively, 
even when they disagree about the whens and hows. I take the extreme pov in 
these discussions, because someone has to. The wider C++ community ignores Qt, 
and I feel that's to the detriment of both. Some try to fork the project. I 
prefer to work within it, as someone who was but a consumer of Qt API for 
(still) most of his professional career, but who also "gets" boost and std. 
One reason why Effective Qt doesn't really get off the ground is that it's often 
easier to just fix the problem at the root instead of writing about it.

> QModelIndex is perfectly fine if you use it as intended, as
> short lived reference into a tree model.

Exactly.. And my point is:
  quote =~ s/QModelIndex/const-&/;
  quote =~ s/tree model/object/;

Thanks,
Marc


-- 
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt Experts



More information about the Development mailing list