[Development] Exporting classes wholesale

Marc Mutz marc.mutz at qt.io
Wed Sep 4 10:56:24 CEST 2024


Hi,

TL;DR: Never export non-polymorphic classes at class-level and always 
define destructors of polymorphic classes, and define them out-of-line.


The class-level export macro used to be a trigger for syncqt to generate 
a forwarding QClass header, so every public class had them in the past, 
and we have a rich history of exported classes.

Over the years, however, we have had a variety of issues with such 
classes as opposed to those that export only member functions that are 
defined out-of-line and expected to be called from outside the module.

An (incomplete) list of these issues can be found in TTLOFIR:
https://wiki.qt.io/Things_To_Look_Out_For_In_Reviews#Value_Classes Item 6

These issues are subtle and many took _months_ to figure out.

We have therefore begun, over time, to favour _not_ exporting 
non-polymorphic classes at class level in order to limit similar 
problems going forward. Syncqt has been fixed ages ago. Yes, it's more 
work to repeat the macro on most function instead of once at class 
level, but we trade more obvious typing against less subtle issues 
cropping up later. Minimizing typing for Qt class authors is not a 
design goal (and QtC's ALT-Down functionality for block editing works 
wonders for adding this).

I've distilled this knowledge over time into the rule combination you 
see in the TL;DR: at the top of this email. This combination of rules 
has no False Positives that I am aware of. That means following these 
rules, your code is _always_ correct (within the scope of the rules).

It's pretty rare to find rules in C++ that are that clear-cut. It's 
usually "prefer to" or "avoid', with tons of exceptions.

Not here. There are no exceptions, and I think this will be one of the 
first Axivion checks we'd enable if and when we get to run it on the CI 
and report results in Gerrit.

I'm happy to discuss alternatives with anyone who thinks we can relax 
that rule to continue to add non-polymorphic classes with class-level 
exports, but I expect more than "I don't like it". I expect a concrete 
alternative rule with a FP rate not higher than the one posted here. 
Note that I, at least, never saw most of the issues listed in TTLOFIR 
coming before they hit us. So it's also very hard to argue that some 
classes "never will run into this". We just don't know what else will 
crop up, until it does.

So I maintain that the TL;DR: is the soundest engineering practice for 
exporting classes, and should be followed - without exception.

Thanks,
Marc

PS: if you wonder about the second part of the rule, that's 
https://wiki.qt.io/Things_To_Look_Out_For_In_Reviews#Polymorphic_Classes 
Item 1

-- 
Marc Mutz <marc.mutz at qt.io> (he/his)
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B


More information about the Development mailing list