summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2020-08-31 11:58:53 +0200
committerAndrei Golubev <andrei.golubev@qt.io>2020-09-10 14:21:47 +0200
commit7a15d71def74cd2cb774534df04df7f9bbdd6d1f (patch)
tree12facc99977c2be11e02cc550c52f0fb96bc04e0 /src/corelib/tools
parenta81859a3c8d0f8b4367fc63988e1d653d34ed48a (diff)
Fix possible corner cases in qarraydataops.h
Updated moveNonPod function to behave correctly under exceptions being thrown. This is the version that was implemented at some point but then got changed prior to merge. Added tests for moveInGrowthDirection (which uses moveNonPod in general case) to verify that range movements are correctly done Updated QCommonArrayOps access modifier from private to protected to allow testing of internal stuff by subclassing Task-number: QTBUG-84320 Change-Id: Idb994a72ee601762e32248670cdc7819aaca0088 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qarraydataops.h20
1 files changed, 11 insertions, 9 deletions
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 0230677330..fe71b41d5c 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -1039,7 +1039,7 @@ struct QCommonArrayOps : QArrayOpsSelector<T>::Type
using iterator = typename Base::iterator;
using const_iterator = typename Base::const_iterator;
-private:
+protected:
using Self = QCommonArrayOps<T>;
// Tag dispatched helper functions
@@ -1116,6 +1116,11 @@ private:
--start;
}
+ // re-created the range. now there is an initialized memory region
+ // somewhere in the allocated area. if something goes wrong, we must
+ // clean it up, so "freeze" the position for now (cannot commit yet)
+ destroyer.freeze();
+
// step 2. move assign over existing elements in the overlapping
// region (if there's an overlap)
while (e != begin) {
@@ -1124,18 +1129,15 @@ private:
*start = std::move_if_noexcept(*e);
}
- // re-created the range. now there is an initialized memory region
- // somewhere in the allocated area. if something goes wrong, we must
- // clean it up, so "freeze" the position for now (cannot commit yet)
- destroyer.freeze();
-
// step 3. destroy elements in the old range
const qsizetype originalSize = this_->size;
- start = oldRangeEnd; // mind the possible gap, have to re-assign
- while (start != begin) {
+ start = begin; // delete elements in reverse order to prevent any gaps
+ while (start != oldRangeEnd) {
// Exceptions or not, dtor called once per instance
+ if constexpr (std::is_same_v<std::decay_t<GrowthTag>, GrowsForwardTag>)
+ ++this_->ptr;
--this_->size;
- (--start)->~T();
+ (start++)->~T();
}
destroyer.commit();