假设我们有一个功能商店
void store(const QByteArray& data);
此功能的工作是取data
并将其存储起来。遗憾的是,如果参数是使用QByteArray::fromRawData(ptr, size)
创建的,那么这样做是不安全的,因为它及其所有副本都要求ptr
保持有效。
因此,store
没有选择禁止其调用者传入此类数组,以便将data
视为立体声中的const char*
或强制执行深层复制detach
。所有这一切都不令人满意,特别是后者会影响性能,因为如果data
在传递给store
之前被COW复制,我们将进行不必要的深层复制。
QByteArray
有一个private
函数nulTerminated
,其实现似乎正是我想要的:如果它不拥有内存,那么它就是深拷贝。如果它拥有内存,它只会返回*this
。
真的有两个问题
是否有使用public
设施的解决方法?
Qt文档提到ptr
只能在返回值的生命周期及其任何副本中保持活动状态。如果您说.right(.size())
,它似乎不是副本,因此Qt需要根据文档制作深层副本。但它真的这样做了吗?
答案 0 :(得分:2)
查看源代码(例如here),ba.right(ba.size());
实际上是简单的浅拷贝,几乎是无操作,所以这不适合你。在任何情况下,依赖于没有文档支持的任何行为都有点不安全,在未来的Qt版本中可能会在没有通知的情况下进行更改。
话虽如此,QByteArray::detach()
没有证件,但公开。它将对使用fromRawData()
创建的数组执行深层复制,但不会对已经未共享的数据执行深度复制,并且认为这不太可能发生变化。示范:
QByteArray ba1 = QByteArray::fromRawData("foo", 4);
QByteArray ba2("foo");
qDebug() << (void*)ba1.constData() << (void*)ba2.constData();
ba1.detach(); ba2.detach();
qDebug() << (void*)ba1.constData() << (void*)ba2.constData();
上面的输出例如:
0x804b960 0x93ebfd8
0x93d2170 0x93ebfd8
查看源代码,IS_RAW_DATA
macro位于 qbytearray.cpp 文件中,我没有发现任何可以使用公共接口利用它的方法。因此,要做你想做的事似乎是不可能的,detach()
是你能得到的最接近的,即使QByteArray::squeeze()
也没有分离原始数据。
答案 1 :(得分:0)
这听起来更像是一个概念问题,而不是技术问题。
store()
试图获得绝对所有权,但是在QByteArray上“获得所有权”在概念上没有多大意义。副本可能会与其他人共享其内存,也可能不会共享,或者可能是由原始数据创建的,因此在后台进行了一个隐藏的所有权处理,整个类旨在将其隐藏给您。总体而言,整个隐式共享事物与现代的显式所有权转让范式并不能很好地融合在一起,并且QByteArray通过提供原始数据功能进一步使事务复杂化。
如果可能的话,接受一个非隐式共享的容器,该容器对它们的内容拥有绝对所有权(例如std :: string,它很容易通过QvalueArray :: toStdString()生成),通过rvalue强制调用者进行复制是最好的选择。