summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qbytearray.cpp
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-05-19 14:35:52 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2019-05-19 16:33:56 +0200
commitc2d2757bccc68e1b981df059786c2e76f2969530 (patch)
tree8f1f9fd3c82500c0366e6ac1f1043db86cfc1101 /src/corelib/tools/qbytearray.cpp
parentc9b7cc349a13b722ecd636ec4eb8e21f9f712add (diff)
QString/QByteArray: detach immediately in operator[]
Unlike any other implicitly shared container, QString/QByteArray have a "lazy detach" mechanism: their operator[] returns a special object; assignment into that object will actually detach. In other words: QString a("Hello"); QCharRef c = a[0]; // does not detach c = 'J'; // detach happens here This allows this behavior: QString a("Hello"); QCharRef c = a[0]; QString b = a; c = 'J'; // detach happens here assert(a == "Jello"); assert(b == "Hello"); Note that this happens only with operator[] -- the mutating iterator APIs instead detach immediately, making the above code have visible side effects in b (at the end, b == "Jello"). The reasons for this special behavior seems to have been lost in the dawn of time: this is something present all the way back since Qt 2, maybe even Qt 1. Holding on to a "reference" while taking copies of a container is documented [1] to be a bad idea, so we shouldn't double check that the users don't do it. This patch: 1) adds an immediate detach in operator[], just like all other containers; 2) adds a warning in debug builds in case QByteRef/QCharRef is going to cause a detach; 3) marks operator[] as [[nodiscard]] to warn users not using Clazy about the (unintended) detach now happening in their code. This paves the way for removal of QCharRef/QByteRef, likely in Qt 7. [1] https://doc.qt.io/qt-5/containers.html#implicit-sharing-iterator-problem [ChangeLog][QtCore][QString] QString::operator[] detaches immediately. Previously, the detach was delayed until a modification was made to the string through the returned QCharRef. [ChangeLog][QtCore][QByteArray] QByteArray::operator[] detaches immediately. Previously, the detach was delayed until a modification was made to the byte array through the returned QByteRef. Change-Id: I9f77ae36759d80dc3202426a798f5b1e5fb2c2c5 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/tools/qbytearray.cpp')
-rw-r--r--src/corelib/tools/qbytearray.cpp30
1 files changed, 21 insertions, 9 deletions
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index c89fb078f7..9816b5cb32 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -1540,8 +1540,11 @@ QByteArray &QByteArray::operator=(const char *str)
\note Before Qt 5.14 it was possible to use this operator to access
a character at an out-of-bounds position in the byte array, and
then assign to such position, causing the byte array to be
- automatically resized. This behavior is deprecated, and will be
- changed in a future version of Qt.
+ automatically resized. Furthermore, assigning a value to the
+ returned QByteRef would cause a detach of the byte array, even if the
+ byte array has been copied in the meanwhile (and the QByteRef kept
+ alive while the copy was taken). These behaviors are deprecated,
+ and will be changed in a future version of Qt.
\sa at()
*/
@@ -5062,10 +5065,15 @@ QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteA
namespace QtPrivate {
namespace DeprecatedRefClassBehavior {
-void warn(EmittingClass c)
+void warn(WarningType w, EmittingClass c)
{
+ static const char deprecatedBehaviorString[] =
+ "The corresponding behavior is deprecated, and will be changed"
+ " in a future version of Qt.";
+
const char *emittingClassName = nullptr;
const char *containerClassName = nullptr;
+
switch (c) {
case EmittingClass::QByteRef:
emittingClassName = "QByteRef";
@@ -5077,12 +5085,16 @@ void warn(EmittingClass c)
break;
}
- qWarning("Using %s with an index pointing outside"
- " the valid range of a %s."
- " The corresponding behavior is deprecated, and will be changed"
- " in a future version of Qt.",
- emittingClassName,
- containerClassName);
+ switch (w) {
+ case WarningType::OutOfRange:
+ qWarning("Using %s with an index pointing outside the valid range of a %s. %s",
+ emittingClassName, containerClassName, deprecatedBehaviorString);
+ break;
+ case WarningType::DelayedDetach:
+ qWarning("Using %s with on a %s that is not already detached. %s",
+ emittingClassName, containerClassName, deprecatedBehaviorString);
+ break;
+ }
}
} // namespace DeprecatedRefClassBehavior
} // namespace QtPrivate