【问题标题】:QListWidget deleting QListWidgetItem causes segmentaion faultQListWidget 删除 QListWidgetItem 导致分段错误
【发布时间】:2021-02-22 10:16:04
【问题描述】:

我有一个 C++ 应用程序,我正在读取 pcap 文件格式并处理 USB 数据包。对于每个数据包,我想创建一个QListWidgetItem,我将在其中存储一些数据,然后将其添加到QListWidget。这就是麻烦开始的地方。根据 QListWidget 文档,插入项目后:

列表小部件将获得该项目的所有权。

所以我认为它在QListWidget 上删除所有QListWidgetItems。这些项目添加得很好,但是当我关闭我的应用程序时(我想那就是当 desctructor od QListWidget 被调用,所以他正在调用每个 QListWidgetItem 的 desctructor)我得到 delete_scalar exception。根据调用堆栈,删除一些 QListWidgetItem 会触发它:

我的代码片段(为 pcap 文件中的每个数据包调用此函数,并负责创建和添加项目):

 void ItemManager::ProcessPacket(QByteArray packetData)
    {
        const unsigned char* packet = (unsigned char*)packetData.data();
        PUSBPCAP_BUFFER_PACKET_HEADER usbh = (PUSBPCAP_BUFFER_PACKET_HEADER)packet;
    
        QListWidgetItem* item = new QListWidgetItem;
    
        //set USBPCAP header to item
        QByteArray usbhArray((const char*)packet, sizeof(USBPCAP_BUFFER_PACKET_HEADER));
        item->setData(dataHolder->USBPCAP_HEADER_DATA, QVariant(usbhArray));
        packet += sizeof(USBPCAP_BUFFER_PACKET_HEADER);
    
        if (usbh->transfer == USBPCAP_TRANSFER_ISOCHRONOUS || usbh->transfer == USBPCAP_TRANSFER_CONTROL) //check for optional header data
        {
            int additionalDataSize = usbh->headerLen - sizeof(USBPCAP_BUFFER_PACKET_HEADER);
            if (additionalDataSize > 0)
            {
                //set additional header data to item
                QByteArray additionalDataArray((const char*)(packet), additionalDataSize);
                item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant(additionalDataArray));
                packet += additionalDataSize;
            }
            else
            {
                item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant()); //QVariant creates invalid QVariant, later i just need to check with QVariant::isValid()
            }
        }
        else
        {
            item->setData(dataHolder->TRANSFER_OPTIONAL_HEADER, QVariant());
        }
    
        //set leftover data to item
        QByteArray leftoverDataArray((const char*)packet, usbh->dataLength);
        item->setData(dataHolder->TRANSFER_LEFTOVER_DATA, QVariant(leftoverDataArray));
    
        listWidget->insertItem(listWidget->count(), item);
    }

调用ProcessPacket函数:

void ItemManager::ProcessFile(QString filename, bool liveReading)
{
    if (fileReader.OpenNewFile(filename))
    {
        if (fileReader.ReadFileHeader())
        {
            while (!stopButtonClicked)
            {
                while (!fileReader.EndOfFile())
                {
                    QByteArray packetData = fileReader.GetPacket();
                    if (!pauseButtonClicked)
                    {
                        ProcessPacket(packetData);
                    }
                }

                parent->Refresh();  //this is just calling QCoreApplication::processEvents();

                if (!atBottomOfList)
                {
                    listWidget->scrollToBottom();
                }

                if (liveReading)
                {
                    Sleep(50);
                }
                else
                {
                    return;
                }
            }
        }
    }
}

编辑

我发现只有在通过ItemManager 附加到QListWidget 类时才会发生此问题。在我的主要 Q_OBJECT 类 USB_Packet_Analyzer(其中包含我要附加的 QlistWidget)中,我有插槽 on_OpenButton_clicked(),它看起来像这样:

void USB_Packet_Analyzer::on_OpenButton_clicked()
{
    QString fil = QFileDialog::getOpenFileName(this, "Select source file", ".", "Pcap files (*.pcap)");
    ItemManager manager(ui.listWidget,this);
    manager.ProcessFile(fil, ui.liveCaptureRadioButton->isChecked());
}

ItemManager 中的类构造函数如下所示:

ItemManager::ItemManager(QListWidget* listWidget, USB_Packet_Analyzer* parent)
{
    this->stopButtonClicked = false;
    this->pauseButtonClicked = false;
    this->atBottomOfList = false;
    this->listWidget = listWidget;
    this->parent = parent;
    this->dataHolder = DataHolder::GetDataHolder();
}

现在,如果我在 on_OpenButton_clicked() 插槽中添加项目并关闭应用程序,一切都很好。但是当我创建 ItemManager 实例并在该类中附加项目时,会发生错误。难道是我不允许将QListWidget*作为参数传递?

【问题讨论】:

  • 看起来像是删除了已经释放的内存。您可能想检查一下,您在哪里显式删除了一个 Qt 对象,该对象是另一个 Qt 对象的子对象。
  • @vahancho Qt 对象是什么意思?创建 Qt 应用程序时,我只有 1 个 Q_OBJECT 类。此类拥有QListWidget 的所有权。添加QListWidgetItems 我有另一个类ItemManager 负责读取pcap 文件并添加项目(它有指向QListWidgetItem 的指针用于添加目的)。 ItemManager 类在读完文件后被销毁,但我的主要 Q_OBJECT 类仍然存在。我想它在程序结束前关闭应用程序主窗口后被删除。
  • 很确定没有显示有问题的代码 - 到目前为止,您发布的一切似乎都很好。我怀疑你有一些其他代码正在删除QListWidgetUSB_Packet_Analyzer,然后Qt 尝试再次删除它。您是否在智能指针中存储了任何 QObject 派生类?

标签: c++ qt qlistwidget qlistwidgetitem


【解决方案1】:

您必须在循环中创建一个新项目。您不能重复使用指针,因为没有内容被复制,只有指针存储在 QListWidget 中

【讨论】:

  • 我不确定我是否正确理解了您的答案,但我认为我没有重复使用相同的指针。我编辑了我的问题,所以还有一个调用 ProcessPacket 函数的循环。
  • 你是对的 - 我之前在你的代码中看到了一个循环。您确定不会在其他任何地方删除该项目吗?
  • 是的,这是我与QListWidget 一起工作并向其附加项目的唯一地方。我什至尝试剪切整个 ProcessPacket 函数,并在 while (!fileReader.EndOfFile()) 循环中创建空的 QListWidgetItem 并将其附加到 QlistWidget 并最终得到相同的结果。
  • 那么请创建一个最小的、可重现的示例。
【解决方案2】:

直到今天我还不能完全确定是什么导致了这个错误,但在我修改了我正在使用的 USBPCAP 结构后,它得到了修复。他们使用各种东西,例如#pragma pack(1) , #pragma pack(push) 等等。看起来我遗漏了其中一些,这可能会导致在使用它们时出现一些未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 2011-05-11
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    • 2017-06-11
    相关资源
    最近更新 更多