QByteArray与reserve()的内部重新分配行为
Internal reallocation behaviour of QByteArray vs reserve()
我只是试图优化一些通信堆栈。我使用的是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()
也放弃了预订。
好的。我想我得到了我需要的信息。
显然,预订并不是通过所有方法来维持的。特别是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"
(感谢Alejandro)
更稳定的方法是在每个数据收集/附加序列之前进行reserve()
调用。这并没有将QByteArray的整个生命中的重新分配减少到一次,但至少它在每个数据序列中只使用一次重新分配,否则需要多次重新分配。我认为这是一个可以接受的变通办法。
无论如何,在Qt容器上使用reserve()
之前,应该详细测试其行为,否则容器的行为可能会与预期大不相同。这一点也很重要,因为这些重要的实现细节没有记录在案,并且在未来的Qt版本中可能会发生更改,而无需另行通知。
QByteArray中的operator=
包含下一个代码
int len = qstrlen(str);
if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1))
realloc(len);
它重新分配了内存,如果新的数据长度大于分配的数据长度,或者如果新数据长度小于当前大小且小于(已分配>>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(' ');
buffer.data_ptr()->size = 0;
buffer.append("bar");
cout << "Capacity " << buffer.capacity() << " Buffer " << buffer;
输出为:
Capacity 1000 Buffer foo
Capacity 1000 Buffer bar
线路:
buffer.fill(' ');
将现有缓冲区的内容设置为NULL。它是可选使用的。
线路:
buffer.data_ptr()->size = 0;
data_ptr()方法返回内部结构data的指针,然后通过将其大小变量修改为0,使缓冲区为空。因此,进一步调用append是合法的。
- 新分配指向函数的指针是否合法?
- 变体 - 分配新值时是否清理旧值?
- 分配新的零大小数组可以具有有效价值吗?
- 当我尝试为结构分配新指针时出现堆栈溢出错误
- 在函数返回中返回对新分配的shared_ptr的尊重合法吗
- 如何删除新分配的字符,这也是函数返回值?
- C ++中新分配的int的内存大小,有没有不同更好的方法来查看它?
- OpenSSL:当输出ptr为空时,BIGNUM的bin2bn不会分配新的BIGNUM
- 每次我分配新的位置时,都会隐式地称为destuructor
- 为什么这个指针到指针的二维数组像这样分配新的 int
- 如何创建对象变量,以便每次分配新的指针
- C 新操作员分配新内存
- 编译器忽略运算符新分配
- 方法向量的新/分配的复杂性::p ush_back
- 有没有一种方法可以全局填充新分配/删除分配
- 调用时为 std::function 分配新值
- 为什么我的新分配指针会自动在程序退出上删除
- 如果我尚未为指针分配新值,是否需要删除指针?
- OpenCV:为矩阵元素分配新值
- 在避免新分配的同时,const变量的复杂初始化