【问题标题】:QByteArray of zero size; where do begin() and end() point to?大小为零的 QByteArray; begin() 和 end() 指向哪里?
【发布时间】:2021-09-02 10:29:57
【问题描述】:

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?总是构造正确的左值数组?

附:按值返回QByteArray 的API 不是我的,它来自QCanBusFrame-&gt;payload()

【问题讨论】:

  • frame.getLoad().begin()frame.getLoad().end() 是两个不同对象的迭代器。
  • 啊哈,看起来begin()end() 如果数组的长度为正,则可以指向重用数组,但是当长度为零时没有数组可以指向,所以有些“随机"(每个对象)值可以用于它们。
  • @MikeCAT 是的,这就是我的观点。为什么他们使用这些随机值而不是 nullptr?
  • 如果您尝试 constBegin 和 constEnd,您会发现它“有效”。但是..不推荐。您应该将返回值保存在中间变量中,最好是 const,以避免 COW。
  • @Amomum 通常,不同容器的迭代器是不兼容的。容器的每个副本都是不同的容器,即使在底层实现了“写入时复制”方案。

标签: c++ qt qbytearray


【解决方案1】:

“写入时复制”意味着它在写入之前复制。现在,当您调用begin() 时,它会返回一个迭代器,您可以使用它写入 到容器,而容器不知道。那么,该类应该做些什么来避免(可能)使共享状态无效?它应该复制整个事情。这就是你的情况。你会得到 2 个副本,以及指向不同缓冲区的迭代器。

【讨论】:

  • 谢谢,这听起来合乎逻辑:)
【解决方案2】:

您在拨打std::copy 时拨打了两次frame.getLoad()。他们将返回不同的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> );

【讨论】:

    猜你喜欢
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 2019-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多