diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2020-08-31 11:58:53 +0200 |
---|---|---|
committer | Andrei Golubev <andrei.golubev@qt.io> | 2020-09-10 14:21:47 +0200 |
commit | 7a15d71def74cd2cb774534df04df7f9bbdd6d1f (patch) | |
tree | 12facc99977c2be11e02cc550c52f0fb96bc04e0 /src/corelib/tools | |
parent | a81859a3c8d0f8b4367fc63988e1d653d34ed48a (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.h | 20 |
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(); |