QArrayData是qt中很多常用流操作类型的成员的最顶层父类。比如在QByteArray,QString等中,都是以Data*的形式而作为流操作类型的数据成员,作为私有被操作对象的身份存在。
Data类型都为QTypedArrayData<T>,而QTypedArrayData就是继承自QArrayData。QTypedArrayData作为迭代器层,添加了一些迭代器相关的底层逻辑。QArrayData对象使用时,对内存的访问访问都是超过该对象本身的内存范围的。
QArrayData的数据成员如下:
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1;
qptrdiff offset; // in bytes from beginning of header
。。。。
x64下,sizeof(QArrayData) == 24 ,ref为4字节;size为4字节,记录所存数据的大小;alloc为31位,记录所分配的内存大小。capacityReserved为1位,offset为64为,记录所存数据,从与QArrayData 对象的地址的偏移值。
QArrayData虽然值有24字节,但是每次为存储数据申请内存块的时候,给申请的大小+24或得指针。然后将新申请的内存赋值给QArrayData*变量。也就是说强制对内存块的嵌入一个QArrayData的header,并初始化header中的size alloc offset等信息。也就是说正常来讲x64下初始化的QArrayData对象的offset就等于24。这里需要注意的是,QArraytData对象虽然只有24字节,但是却管控者alloc+24大小的内存空间。
QArrayData::allocate的代码:
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options) Q_DECL_NOTHROW
{
// Alignment is a power of two
Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData)
&& !(alignment & (alignment - 1)));
// Don't allocate empty headers
if (!(options & RawData) && !capacity) {
#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
if (options & Unsharable)
return const_cast<QArrayData *>(&qt_array_unsharable_empty);
#endif
return const_cast<QArrayData *>(&qt_array_empty);
}
size_t headerSize = sizeof(QArrayData);
// Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
// can properly align the data array. This assumes malloc is able to
// provide appropriate alignment for the header -- as it should!
// Padding is skipped when allocating a header for RawData.
if (!(options & RawData))
headerSize += (alignment - Q_ALIGNOF(QArrayData));
if (headerSize > size_t(MaxAllocSize))
return 0;
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
& ~(alignment - 1);
#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
header->ref.atomic.store(bool(!(options & Unsharable)));
#else
header->ref.atomic.store(1);
#endif
header->size = 0;
header->alloc = capacity;
header->capacityReserved = bool(options & CapacityReserved);
header->offset = data - quintptr(header);
}
return header;
}
在moc中对QArrayData有一种独特用法:
struct qt_meta_stringdata_Base_t {
QByteArrayData data[9];
char stringdata0[34];
};
static const qt_meta_stringdata_Base_t qt_meta_stringdata_Base = {..}
qt_meta_stringdata_Base 是用于记录类的类名、函数成员和数据成员名称的,名称以\0结尾结成一串存放stringdata0中。moc中将类中函数成员和数据成员从0开始顺序标号,成员数量与qt_meta_stringdata_Base 的data数量是一致的。qt_meta_stringdata_Base.data用于记录对应下标的函数的名称在stringdata0中的位置和大小。这里的9个QByteArrayData共同管理着(这里更确切来讲应该是 操作着)同一块内存:stringdata0,只是每个对象访问的位置是错开的。