6

我只是试图优化一些通信堆栈。我正在使用 Qt 5.3.2 / VS2013。

堆栈使用 QByteArray 作为数据缓冲区。我打算使用capacity()reserve()方法在数据大小增长时减少不必要的内部缓冲区重新分配。然而,QByteArray 的行为被证明是不一致的。保留的空间有时似乎被隐式挤压。

我可以提取以下演示应用字符串追加、字符串分配和字符追加到三个缓冲区。这些单个操作似乎保留了内部缓冲区大小(使用 获得capacity())。但是,当将这三个操作中的每一个应用于相同的 QByteArray 时,保留的大小会发生变化。这种行为在我看来是随机的:

QByteArray x1; x1.reserve(1000);
x1.append("test");
qDebug() << "x1" << x1.capacity() << x1;

QByteArray x2; x2.reserve(1000);
x2 = "test";
qDebug() << "x2" << x2.capacity() << x2;

QByteArray x3; x3.reserve(1000);
x3.append('t');
qDebug() << "x3" << x3.capacity() << x3;

QByteArray x4; x4.reserve(1000);
x4.append("test");
x4.append('t');
x4 = "test";
qDebug() << "x4" << x4.capacity() << x4;

预期的输出将是:

x1 1000 "test"
x2 1000 "test"
x3 1000 "t"
x4 1000 "test"

但实际输出是:

x1 1000 "test"
x2 1000 "test"
x3 1000 "t"
x4 4 "test"

有人对这种奇怪的行为有解释吗?

更新:看起来clear()也放弃了预订。

4

3 回答 3

3

好的。我想我得到了我需要的信息。

显然,保留并没有超出所有方法。特别是似乎取消了预订clear()operator=()在这种情况下,operator=()由于使用的数据的隐式共享,实际上不可能保留保留operator=(QByteArray)

这也意味着 QByteArray 的保留机制是针对不同的用例而制定的。试图在 QByteArray 对象的整个生命周期中保持保留是很困难的。

对于我的用例,似乎有一种解决方法,使用truncate(0)代替clear()operator=()

QByteArray buffer;
buffer.reserve(1000);
buffer.append("foo");
qDebug() << "buffer" << buffer.capacity() << buffer;

buffer.truncate(0);
buffer.append("bar");
qDebug() << "buffer" << buffer.capacity() << buffer;

这打印:

buffer 1000 "foo"
buffer 1000 "bar"

(感谢亚历杭德罗)

更稳定的方法是reserve()在每个数据收集/附加序列之前进行调用。这不会在 QByteArray 的整个生命周期中将重新分配减少到一个,但至少它对每个数据序列使用一个重新分配,否则它需要多次重新分配。我认为这是一个可以接受的解决方法。

无论如何,reserve()在 Qt 容器上使用之前,应该详细测试行为,否则可能会发生容器的行为与预期大不相同的情况。这也很重要,因为这些基本实现细节没有记录在案,并且在未来的 Qt 版本中可能会发生更改,恕不另行通知。

于 2014-11-12T12:06:59.270 回答
2

operator=在 QByteArray 中包含下一个代码

int len = qstrlen(str);
if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1))
realloc(len);

它重新分配内存,如果新数据长度大于分配的或者如果新数据长度小于当前大小并且小于(已分配 >> 1)

于 2014-11-08T20:26:10.233 回答
1

没有直接的方法可以利用 QByteArray 类中的 reserve() 方法。我尝试执行以下操作:

QByteArray buffer;
buffer.reserve(1000);
buffer.append("foo");
cout << "Capacity " << buffer.capacity() << " Buffer " << buffer;

buffer.truncate(0);
buffer.append("bar");
cout << "Capacity " << buffer.capacity() << " Buffer " << buffer;

输出是:

Capacity 1000 Buffer foo
Capacity 8 Buffer bar

发生这种情况是因为,在缓冲区上调用 truncate 会调用“resize”方法,该方法实际上会释放保留的内存。要使其工作,没有使用文档化的 QByteArray API 的直接方法。我可以想出一个办法,可以试一试。

QByteArray buffer;
buffer.reserve(1000);
buffer.append("foo");
cout << "Capacity " << buffer.capacity() << " Buffer " << buffer;

buffer.fill('\0');
buffer.data_ptr()->size = 0;
buffer.append("bar");
cout << "Capacity " << buffer.capacity() << " Buffer " << buffer;

输出是:

Capacity 1000 Buffer foo
Capacity 1000 Buffer bar

线:

buffer.fill('\0');

将现有缓冲区的内容设置为 NULL。它是可选的。

线:

buffer.data_ptr()->size = 0;

data_ptr() 方法返回一个内部结构 Data 的指针,然后通过将其大小变量修改为 0,使缓冲区为空。因此,对追加的进一步调用是合法的。

于 2015-04-02T10:22:36.113 回答