summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qbytearray.h
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-05-13 14:33:57 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-05-19 14:24:52 +0200
commit8845caa057cfcf54f7d46621adb3393c13747ffb (patch)
tree5aebf32e9d1abe6b4e93067c83d6e3204f944fd1 /src/corelib/tools/qbytearray.h
parentc7167509acdba006fe6da4ec1866acb214c18197 (diff)
QCharRef/QByteRef: warn when triggering the resizing operator= behavior
The whole reason of QCharRef/QByteRef existence is to have a magic operator=. This operator= delays the actual detach up to the moment something is written into the Ref, thus avoiding spurious detaches to the underlying string/byte array. operator= has also an extra feature, it allows this code to succeed: QString s("abc"); s[10] = 'z'; assert(s == "abc z"); This last behavior is *extremely* surprising. The problem with all of this is that this extra convenience is outweighted by the massive pessimization in the codegen for operator[]; by the maintenance burden (QChar APIs need to be mirrored in QCharRef, etc.), and, for the automatic resize, by the fact that it's an super-niche use case. Cherry on top, std::basic_string does not do that, and no Qt or std container does that. In other words: any other container-like class exhibits UB for out of bounds access. We can't just go and change behavior, though. This is something coming all the way back from Qt 2 (maybe even Qt 1), which means we can't deprecate it at short notice. This patch simply adds a warning in debug builds in case the special resizing behavior is triggered. While at it, removes some code duplication in QByteRef. [ChangeLog][QtCore][QString] The behavior of operator[] to allow implicit resizing of the string has been deprecated, and will be removed in a future version of Qt. [ChangeLog][QtCore][QByteArray] The behavior of operator[] to allow implicit detaching and resizing of the byte array has been deprecated, and will be removed in a future version of Qt. Change-Id: I3b5c5191167f12a606bcf6e513e6f304b220d675 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Diffstat (limited to 'src/corelib/tools/qbytearray.h')
-rw-r--r--src/corelib/tools/qbytearray.h41
1 files changed, 36 insertions, 5 deletions
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index d21cb9b363..5c7229e40d 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -528,6 +528,17 @@ inline void QByteArray::squeeze()
}
}
+namespace QtPrivate {
+namespace DeprecatedRefClassBehavior {
+ enum class EmittingClass {
+ QByteRef,
+ QCharRef,
+ };
+
+ Q_CORE_EXPORT Q_DECL_COLD_FUNCTION void warn(EmittingClass c);
+} // namespace DeprecatedAssignmentOperatorBehavior
+} // namespace QtPrivate
+
class
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_CORE_EXPORT
@@ -540,13 +551,33 @@ QByteRef {
friend class QByteArray;
public:
inline operator char() const
- { return i < a.d->size ? a.d->data()[i] : char(0); }
+ {
+ using namespace QtPrivate::DeprecatedRefClassBehavior;
+ if (Q_LIKELY(i < a.d->size))
+ return a.d->data()[i];
+#ifdef QT_DEBUG
+ warn(EmittingClass::QByteRef);
+#endif
+ return char(0);
+ }
inline QByteRef &operator=(char c)
- { if (i >= a.d->size) a.expand(i); else a.detach();
- a.d->data()[i] = c; return *this; }
+ {
+ using namespace QtPrivate::DeprecatedRefClassBehavior;
+ if (Q_UNLIKELY(i >= a.d->size)) {
+#ifdef QT_DEBUG
+ warn(EmittingClass::QByteRef);
+#endif
+ a.expand(i);
+ } else {
+ a.detach();
+ }
+ a.d->data()[i] = c;
+ return *this;
+ }
inline QByteRef &operator=(const QByteRef &c)
- { if (i >= a.d->size) a.expand(i); else a.detach();
- a.d->data()[i] = c.a.d->data()[c.i]; return *this; }
+ {
+ return operator=(char(c));
+ }
inline bool operator==(char c) const
{ return a.d->data()[i] == c; }
inline bool operator!=(char c) const