[Interest] QueuedConnection, QByteArray, reserve, capacity
Thiago Macieira
thiago.macieira at intel.com
Wed May 31 18:10:09 CEST 2017
On Wednesday, 31 May 2017 02:15:47 PDT qtlist at wadefalk.se wrote:
> First of all, i think reserve() seems not to be reliable for keeping the
> promise of the container's size and memory buffer integrity even under
> normal simple conditions. After having reserved a certain size and then
> modifying the actual length of the QByteArray using resize() to a size LESS
> or EQUAL to the size of the capacity() would unpredictably (not always)
> have the array to reallocate its data and again reducing the capacity. This
> is in my world a breakage of the semantics in the container behavior.
> Expecting the QByteArray::data() not to change the actual memory location
> is then completely false. One of the expectations of the reserve() call is
> to guarantee the container not to reallocate itself unless absolutely
> needed.
It you shrink too much, then it releases the memory. (where "too much" may be
"less than half", I'd have to check the sources)
> But one thing about this that is even worse. I discovered having a set
> capacity of a QByteArray to something and then passing that QByteArray as
> const reference to a signal over a QueuedConnection actually modified the
> capacity() ! (and indeed reallocated the array). The violation of rules in
> this case I feel is even worse and I suspect the moc code does something
> strange to make this happen. I have read the moc code is supposed to take a
> copy of the array and pass that copy to the other thread (this is nice of
> course), but how can that result in the original container in the signal
> emitting thread being reallocated and having its capacity modified? Here we
> are even talking about breakage of const promise.
The signal-slot system treats const references the same as passing by value.
So when you have a queued connection, the system will actually create a copy
behind your back and queue that to the other thread. Please note that this
needs to happen, since the slot is called asynchronously from the emission:
this is the only way to guarantee that the reference that the slot gets is
valid, with no data race issues.
That is also why you cannot pass non-const references via queued connections.
You can pass pointers (the pointer is copied and the pointed object is your
problem).
I *think* we wrote the optimisation that a BlockingQueuedConnection does not
copy, but again I'd have to check the sources.
> If I'm right this is totally unexpected behavior and it should be filed as
> a serious bug I think. Here is a simple example.
Not a bug. This is expected and required behaviour.
>
> #ifndef ASYNCARRAY_H #define ASYNCARRAY_H #include class ASyncArray :
> public QObject { Q_OBJECT public: explicit ASyncArray(QObject *parent =
> nullptr); public slots: void testSlot(const QByteArray& array); signals:
> void testSignal(const QByteArray& array); public slots: }; #endif //
> ASYNCARRAY_H #include #include "asyncarray.h"
> ASyncArray::ASyncArray(QObject *parent) : QObject(parent) { connect(this,
> &ASyncArray::testSignal, this, &ASyncArray::testSlot,
> Qt::QueuedConnection); QByteArray testArray; testArray.reserve(100);
> testArray.resize(50); memset(testArray.data(), 0xaa, testArray.capacity());
> qDebug()
Line breaks anywhere, please? Anyway, not relevant.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
More information about the Interest
mailing list