问题描述
QByteArray 使用写时复制策略,因此复制它们很便宜。我认为这也意味着可以按值传递它们。
然而,当我使用零长度的 QByteArray 时,这个假设似乎被打破了:
struct Frame
{
QByteArray load{0,0}; // zero size,fill with zeroes
QByteArray getLoad() { return load; }
};
Frame frame;
std::copy( frame.getLoad().begin(),frame.getLoad().end(),<somewhere> );
这有时会产生 SEGFAULT,因为 begin()
和 end()
似乎指向完全不同的位置,有时 end()
在数字上小于 begin()
(这会触发调试验证检查MSVC 关于转置指针)。
我目前的理解是,这是因为 frame.getLoad()
构造了一个临时 QByteArray
两次,并且出于某种原因,其中的迭代器指向完全不同的位置 - 当且仅当数组大小为 0 时。
(如果数组大小为零并且实际上没有分配内存,我不确定他们应该指向哪里,但这对我来说仍然很令人惊讶)。
我的理解是否正确?如果是这样 - 我该怎么办?检查零大小的边缘情况?通过引用传递 QByteArray
?总是构造合适的左值数组?
附言API 按值返回 QByteArray
不是我的,它来自 QCanBusFrame->payload()
。
解决方法
“Copy On Write”意味着它会在 write 之前copy。现在,当您调用 begin()
时,它会返回一个迭代器,您可以使用它写入到容器中而无需容器知道。那么,类应该怎么做才能避免(可能)使共享状态无效?它应该复制整个事情。这就是你的情况。您将获得 2 个副本,以及指向不同缓冲区的迭代器。
您在调用 frame.getLoad()
时调用了两次 std::copy
。它们将返回不同的 QByteArray
,因此它们的 begin()
和 end()
没有关系。
您可以让 getLoad()
返回对 load
的引用来解决这个问题。
QByteArray& getLoad() { return load; }
如果您希望 getLoad()
返回 load
的副本,您应该在调用 std::copy
之前将其存储到一个变量中并使用它。
Frame frame;
QByteArray frameLoad = frame.getLoad();
std::copy( frameLoad.begin(),frameLoad.end(),<somewhere> );