QList<T>::operator[]: "index out of range" 中的断言失败

ASSERT failure in QList<T>::operator[]: "index out of range"

本文关键字:range of 失败 断言 out lt gt operator QList index      更新时间:2023-10-16

我知道这个问题已经被问了很多次了,我已经研究并发现了我的代码的哪一部分给出了这个错误。我要求这样做是为了获得该解决方案的替代方案。我正在处理连续接收大数据包的情况。我已经连接了一个信号来读取串行数据,如下所示:

connect(&Serial, SIGNAL(readyRead()), this, SLOT(SerialRead()));

因此,每次当新的串行数据可供读取时,都会调用SerialRead()。我正在尝试读取一个数据包,嗖嗖声长度不固定。现在发生的事情是SerialRead()读取几个字节的数据,然后再次读取。由于数据包长度很大,它无法在一次运行中读取完整的数据包,并且在我拥有完整的数据包之前,我无法在代码中进一步移动。幸运的是,我研究了数据包,发现数据包的第 4 个字节表示数据包的长度。所以现在我有了长度,这意味着我可以检查我是否按照第 4 个字节收到了完整的字节,然后进一步移动。为此,我编写了以下代码:

QString serialData,numberOfBytes;
QStringList serialPacket;
void MainWindow::SerialRead()
{
serialData.append(Serial.readAll());    //reading all the serial data
serialPacket = serialData.split(" ");
numberOfBytes = Convert.ToDec(serialPacket[3]);   //getting the length of the packer
if(serialPacket.count() >= (numberOfBytes.toInt()))  //checking if all the bytes (full packet) is received or not
{
DisplayMessage(serialPacket);
}
}

因此,当我收到完整的数据包时,我会转到我的显示消息函数来处理数据包。现在,当ASSERT Failure错误出现时,我注释掉了numberOfBytes = Convert.ToDec(serialPacket[3]);行及其剩余代码,然后没有错误。所以我认为错误试图说如果 serialPacket[3] 不包含任何数据,那么它就会给出错误。如果这是真的,那么它的替代品是什么。?谁能告诉我一个检查是否收到完整数据包的好方法。?谢谢

编辑:

void MainWindow::SerialRead()
{
serialData.append(Serial.readAll()); //Reading the data
if(!serialData.isEmpty()) //Checking if data is empty or not
{
serialPacket = serialData.split(" ",QString::SkipEmptyParts);
if(serialPacket.contains("CC")) //Checking if it contains "CC"
{
int index = serialPacket.indexOf("CC");
numberOfBytes = Convert.ToDec(serialPacket[index+2]);
if(serialPacket.count() >= ((numberOfBytes.toInt())+2))
{
DisplayMessage(serialPacket);
}
}
}
}

如果在解析器的形式化中使解析更加明确,解码器的性能会更好。双状态计算机将完成这项工作。下面是一个完整的测试用例:

// https://github.com/KubaO/stackoverflown/tree/master/questions/packet-read-43228728
#include <QtTest>
#include <private/qringbuffer_p.h>
// See http://stackoverflow.com/a/32317276/1329652
/// A simple point-to-point intra-process pipe. The other endpoint can live in any
/// thread.
class AppPipe : public QIODevice {
//...
};
class Decoder : public QObject {
Q_OBJECT
QPointer<QIODevice> m_device;
QByteArray m_data;
char m_first;
bool m_isFirst = true;
static constexpr char fromHex(char c) {
return
(c >= '0' && c <= '9') ? (c - '0') :
(c >= 'A' && c <= 'F') ? (c - 'A' + 10) :
(c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
-1;
}
void decode(const QByteArray & src) {
for (auto c : src) {
auto val = fromHex(c);
if (val < 0) continue;
if (m_isFirst)
m_first = val << 4;
else
m_data.append(m_first | val);
m_isFirst = !m_isFirst;
}
}
void onReadyRead() {
// The data has the format "XX XX XX" where X are hex digits.
// Spaces and invalid digits are skipped
decode(m_device->readAll());
if (m_data.size() >= 4) {
auto length = 4 + m_data[3];
if (m_data.size() >= length) {
emit hasMessage(m_data.left(length));
m_data.remove(0, length);
}
}
}
public:
Decoder(QIODevice * dev, QObject * parent = {}) : QObject{parent}, m_device{dev} {
connect(dev, &QIODevice::readyRead, this, &Decoder::onReadyRead);
}
Q_SIGNAL void hasMessage(const QByteArray &);
};
class DecoderTest : public QObject {
Q_OBJECT
AppPipe src{nullptr, QIODevice::ReadWrite};
AppPipe dst{&src, QIODevice::ReadWrite};
Q_SLOT void initTestCase() {
src.addOther(&dst);
}
Q_SLOT void test1() {
Decoder dec(&dst, this);
QSignalSpy spy(&dec, &Decoder::hasMessage);
src.write("0"); // send a partial header
QCOMPARE(spy.size(), 0);
src.write("0 00 00 03 "); // send rest of the header
QCOMPARE(spy.size(), 0);
src.write("0A 0B "); // send partial data
QCOMPARE(spy.size(), 0);
src.write("0C "); // send rest of data
QCOMPARE(spy.size(), 1);
QCOMPARE(dst.bytesAvailable(), 0); // ensure all data has been read
const QByteArray packet{"x00x00x00x03x0Ax0Bx0C", 4+3};
QCOMPARE(spy.first().size(), 1);
QCOMPARE(spy.first().first(), {packet});
}
Q_SLOT void test2() {
Decoder dec(&dst, this);
QSignalSpy spy(&dec, &Decoder::hasMessage);
src.write("BABE0004 C001 DA7En0FAB33"); // send a packet and part of another
QCOMPARE(spy.size(), 1);
src.write("01 ABn");
QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(0).size(), 1);
QCOMPARE(spy.at(1).size(), 1);
const QByteArray packet1{"xBAxBEx00x04xC0x01xDAx7E", 4+4};
const QByteArray packet2{"x0FxABx33x01xAB", 4+1};
QCOMPARE(spy.at(0).first(), {packet1});
QCOMPARE(spy.at(1).first(), {packet2});
}
};
QTEST_GUILESS_MAIN(DecoderTest)
#include "main.moc"

正如其他用户的评论中提到的,您必须确保您尝试接收的数据包在第 4 个索引处有一些数据。以便您可以进一步处理它以计算长度。正如您所说,serialPacket的第 4 个索引将包含长度,您必须设置一些条件,即串行数据包的大小至少包含 4 或 5 个字节。像这样:

if(serialPacket.size()>=5)
{
numberOfBytes = Convert.ToDec(serialPacket[3]);
}
else
{
QMessageBox MessageBox;
MessageBox.setText("Error receving packets");
}