summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qglobal.h
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-01-03 17:18:02 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-10-03 11:47:17 +0200
commit889d40ebe2d9d0e92caea2749608720f7c088173 (patch)
treea68214fbf5a0dc9b1488e4ae79a499dabc1cc445 /src/corelib/global/qglobal.h
parent990e2e4fb8ef546b89b5e83e659771edd5b4ed3e (diff)
Centralize the implementation of move assignment operators
At the moment we have two main strategies for dealing with move assignment in Qt: 1) move-and-swap, used by "containers" (in the broad sense): containers, but also smart pointers and similar classes that can hold user-defined types; 2) pure swap, used by containers that hold only memory (e.g. QString, QByteArray, ...) as well as most implicitly shared datatypes. Given the fact that a move assignment operator's code is just boilerplate (whether it's move-and-swap or pure swap), provide two _strictly internal_ macros to help write them, and apply the macros across corelib and gui, porting away from the hand-rolled implementations. The rule of thumb when porting to the new macros is: * Try to stick to the existing code behavior, unless broken * if changing, then follow this checklist: * if the class does not have a move constructor => pure swap (but consider ADDING a move constructor, if possible!) * if the class does have a move constructor, try to follow the criteria above, namely: * if the class holds only memory, pure swap; * if the class may hold anything else but memory (file handles, etc.), then move and swap. Noteworthy details: * some operators planned to be removed in Qt 6 were not ported; * as drive-by, some move constructors were simplified to be using qExchange(); others were outright broken and got fixed; * some contained some more interesting code and were not touched. Change-Id: Idaab3489247dcbabb6df3fa1e5286b69e1d372e9 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/corelib/global/qglobal.h')
-rw-r--r--src/corelib/global/qglobal.h45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index a6ae741dac..7accb690fa 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -432,6 +432,51 @@ Q_DECL_UNUSED constexpr Deprecated_t Deprecated = {};
Q_DISABLE_MOVE(Class)
/*
+ Implementing a move assignment operator using an established
+ technique (move-and-swap, pure swap) is just boilerplate.
+ Here's a couple of *private* macros for convenience.
+
+ To know which one to use:
+
+ * if you don't have a move constructor (*) => use pure swap;
+ * if you have a move constructor, then
+ * if your class holds just memory (no file handles, no user-defined
+ datatypes, etc.) => use pure swap;
+ * use move and swap.
+
+ The preference should always go for the move-and-swap one, as it
+ will deterministically destroy the data previously held in *this,
+ and not "dump" it in the moved-from object (which may then be alive
+ for longer).
+
+ The requirement for either macro is the presence of a member swap(),
+ which any value class that defines its own special member functions
+ should have anyhow.
+
+ (*) Many value classes in Qt do not have move constructors; mostly,
+ the implicitly shared classes using QSharedDataPointer and friends.
+ The reason is mostly historical: those classes require either an
+ out-of-line move constructor, which we could not provide before we
+ made C++11 mandatory (and that we don't like anyhow), or
+ an out-of-line dtor for the Q(E)DSP<Private> member (cf. QPixmap).
+
+ If you can however add a move constructor to a class lacking it,
+ consider doing so, then reevaluate which macro to choose.
+*/
+#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Class) \
+ Class &operator=(Class &&other) noexcept { \
+ Class moved(std::move(other)); \
+ swap(moved); \
+ return *this; \
+ }
+
+#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class) \
+ Class &operator=(Class &&other) noexcept { \
+ swap(other); \
+ return *this; \
+ }
+
+/*
No, this is not an evil backdoor. QT_BUILD_INTERNAL just exports more symbols
for Qt's internal unit tests. If you want slower loading times and more
symbols that can vanish from version to version, feel free to define QT_BUILD_INTERNAL.