c++qtqbytearray

QByteArray of zero size; where do begin() and end() point to?


QByteArray uses copy-on-write strategy, so copying them is cheap. I assumed that also means that it's okay to pass them by value.

However, this assumption seems to break when I use QByteArray with zero length:

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> );

This sometimes produces SEGFAULT because begin() and end() seem to point in completely different locations, sometimes end() is numerically less then begin() (and that triggers debug verification check in MSVC about transposed pointers).

My current understanding is that's because frame.getLoad() constructs a temporary QByteArray twice, and for some reason iterators inside them point to completely different locations - if and only if array size is 0. (I'm not sure where they should point if array size is zero and no memory is actually allocated but this still seems very surprising to me).

Is my understanding of this correct? If so - what should I do? Check for zero-sized edge case? Pass QByteArray by reference? Always construct proper lvalue array?

P.S. API returning QByteArray by value is not mine, it's from QCanBusFrame->payload().


Solution

  • You are calling frame.getLoad() twice in your call of std::copy. they will return different QByteArray, so their begin() and end() has no relation.

    You can have getLoad() return the reference to load to overcome this problem.

    QByteArray& getLoad() { return load; }
    

    If you want getLoad() return the copy of load, you should store that to a variable before calling std::copy and use that.

    Frame frame;
    QByteArray frameLoad = frame.getLoad();
    std::copy( frameLoad.begin(), frameLoad.end(), <somewhere> );