[Development] QList

Marc Mutz marc.mutz at kdab.com
Fri Mar 24 13:31:32 CET 2017


On Friday 24 March 2017 11:34:37 Edward Welbourne wrote:
> Marc Mutz (23 March 2017 20:41)
> 
> > Do I need to mention QPolygon and what pain it's inheritance from
> > QVector<QPoint> has caused? (FTR: cf. end of qvector.h and
> > qvector_msvc.cpp).
> 
> well, I - for one - can only see a minor problem; so, since you *have*
> mentioned it, perhaps you could elaborate ?  I hadn't realised QVector
> wasn't public - I can see how that would be an argument for the
> inheritance to be private.  Is there more to the problem than that ?
> You make it sound a bigger deal than anything I can see in the source -
> so please educate me,

Well, where should I start? There are two principles that interact to cause 
all kinds of mayhem, both of them on Windows:

1. When a class is exported, all of its members are exported. That includes
   the base class' members, regsardless of whether they were exported
   themselves or not.
2. When an inline function is exported (by itself or via a class-level
   export), MSVC calls the copy in the DLL. I don't know whether it places a
   copy in the user's executable at all. You can prevent this behaviour by
   marking each such function with Q_ALWAYS_INLINE.

(2) means we can't change signatures of exported inline functions, because 
that would be BiC on Windows/Debug. On all other platforms, incl. 
Windows/Release, renaming, removing, changing the signature of, an inline 
function, exported or not, is always BC. It may be SiC, but it's always BC.

We have many use-cases that assume that inline functions do not form part of 
the ABI:

a. QVector and other container change the signature of begin() etc to
   implement QT_STRICT_ITERATORS. As a consequence, QT_STRICT_ITERATORS fails
   for (at least) QXmlStreamAttributes, inheriting QVector, because only one
   of the two overloaded functions gets exported while the other one is not.

You may disregard this as a container-only thing, but it's far more 
widespread:

b. We also assume we can #if Q_COMPILER away functions as long as they are
   inline. You see where this is going? Once MS actually keeps BC themselves,
   and afaiu, they plan to do so for 2015 -> 2017, this will cause BiC in all
   exported classes whenever 2015 lacks a feature that 2017 provides.

I don't know why Thiago thinks these reasons are not worth stopping exporting 
non-polymorphic classes for, but I'm absolutely convinced that exporting only 
non-inline functions in such classes is the only correct way to deal with the 
Microsoft platform.

Non-polymophic classes should decide what they want to be:

I. if they want to be pimpl'ed, they should have most functions out-of-line.
   In this case, it's ok to export the whole class, but all inline functions
   should have to be marked as Q_ALWAYS_INLINE from the outset.

II. if they want to be thin abstractions, most functions should be inline. The
   class should not be exported, only out-of-line functions should be. To
   prevent inheriting such classes, thereby exporting their inline functions,
   such classes should be agressively marked as final.

Polymophic classes should follow the rules of (I) (class-level exporting them 
is required here) plus have all their virtuals (incl. esp. their dtor) defined 
out-of-line.

HTH,
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, C++ and OpenGL Experts



More information about the Development mailing list