【问题标题】:QtSerialPort has unavailable data, segmentation fault under Windows 8 onlyQtSerialPort 数据不可用,仅在 Windows 8 下出现分段错误
【发布时间】:2014-09-11 21:18:43
【问题描述】:
const QSerialPortInfo* serialPortInfo = nullptr;

bool PortManager::setPort(QString portName) {
    const QList<QSerialPortInfo> infoList = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo portInfo : infoList) {
        if (portInfo.portName() == portName && serialPortInfo != &portInfo) {
            serialPortInfo = &portInfo;
        }
    }
    if (serialPortInfo != nullptr) {
        if (portName != "" && serialPortInfo->isValid()) { //segmentation fault
            if (serialPort->isOpen()) {
                serialPort->close();
            }
            serialPort = new QSerialPort(*serialPortInfo, this);
            if (serialPort->open(QIODevice::ReadWrite)) {
                if (serialPort->clear()) {
                    if (serialPort->setBaudRate(QSerialPort::Baud38400, QSerialPort::AllDirections)
                            && serialPort->setFlowControl(QSerialPort::NoFlowControl)
                            && serialPort->setParity(QSerialPort::NoParity)) {
                        isPortSet = true;
                    }
                    .
                    .
                    .

这是我的代码,适用于 Linux 和 Windows 7。现在我正在 Windows 8 上测试它,我在 this->serialPortInfo->isValid() (以及 serialPortInfo 的任何其他函数)上遇到分段错误.任何特定 QSerialPortInfo 对象的所有数据都是“不可用的”(如调试器所述),在我看来,我没有使用它们的特权。在 Linux 上,我必须是 uupc(如果我没记错的话)组的成员才能没有这样的错误,但在 Windows 7 上我不必做任何事情。我以“管理员身份”运行 Qt Creator,但没有帮助;也许我必须以某种方式告诉它也以管理员身份运行 qmake?不过这只是我的猜测,可能原因不一样……

【问题讨论】:

  • 稍微吹毛求疵,您知道 Windows 没有任何命名“分段错误”吗?
  • @JoachimPileborg:不管它有什么,它被 Qt Creator 称为“SIGSEGV: Segmentation fault”;但我在 MinGW 上工作,它基本上是一个 Linux,所以......我对 Windows 不太了解。 ;-) 它有什么改变吗?

标签: c++ windows qt qt5 qtserialport


【解决方案1】:

这是 Qt 鼓励您在不打算更改内容时在 for 循环中使用 const 引用的典型案例。看到这一行:

for (const QSerialPortInfo portInfo : infoList) {

你应该写这个来让它工作:

for (const QSerialPortInfo &portInfo : infoList) {
//                         ^

原因很简单,您正在创建一个临时副本,该副本在超出范围时会被销毁,而不是使用原始列表项,因为原始列表在外部,因此会比循环寿命更长。

您一定很高兴它完全可以在 Linux 和 Windows 7 上运行。我对此感到非常惊讶,即使可以,它也可能在任何特定时刻对您的客户造成冲击。

话虽如此,您的概念总体上似乎是错误的。您查询所有项目以找到一个专用端口。像这样首先构造您的 QSerialPortInfo 实例会更清楚:

serialPortInfo = new QSerialPortInfo(portName);

此外,您确实应该使用堆栈对象而不是堆。像这样的信息类不应该在堆上分配,尤其是在没有智能指针管理的情况下。

不用说,当它们是邪恶的时候创建一个全局变量是不好的,尤其是在这种情况下,你可以通过将它放入方法本身来避免它。

如果您停止使用指针,您也可以删除以下行:

if (serialPortInfo != nullptr) {

更不用说,在 Qt 应用程序中,无论如何你都应该使用 Q_NULLPTR,因为它在没有 C++11 支持的情况下也可以工作,同样的原因也适用于你原来的 for 循环。我会使用 Qt 中的 foreach,但话又说回来,我认为整体概念是错误的。

似乎您甚至不需要QSerialPortInfo 实例,因为您使用的只是可以直接传递给QSerialPort 对象的名称。因此,您甚至可以摆脱 QSerialPortInfo 对象。

因此,我的建议是完全删除 for 循环和 QSerialPortInfo 实例并直接在方法中使用 QSerialPort

【讨论】:

  • 我按照你说的做了,所以没有 QSerialPort 实例或任何循环,但它只导致分段错误开始出现在 QSerialPort 创建上,而不是 QSerialPortInfo 上......但是当我进一步了解你的建议并将指针更改为真实对象-创建很好,但询问 serialPort.portName() 仍然会导致分段错误。但是这种变化表明代码中的一些随机 timeout() 信号存在另一个错误......基本上我觉得我将不得不重写所有不好的东西,因为在 Windows 7 上一切都很好。:/
  • 但我不明白这背后的原因......对我来说,这段代码应该可以工作,而且它现在可以在我的笔记本电脑上工作......所以那里没有“错误”,对吧?
  • @smsware:重用已破坏的对象存在未定义的行为。就像我在答案中写的那样,我很惊讶它现在才爆炸。
【解决方案2】:

问题是这个循环:

for (const QSerialPortInfo portInfo : infoList) {
    if (portInfo.portName() == portName && serialPortInfo != &portInfo) {
        serialPortInfo = &portInfo;
    }
}

变量portInfo 的作用域仅在循环内,并且仅适用于当前迭代。一旦循环迭代,该变量就会被破坏。使用指向被破坏对象的指针是undefined behavior,这可能是您崩溃的原因。

关于如何阻止它,我对您的建议是不要使用指针。而是复制结构。

【讨论】:

  • 为什么不把const &amp; 换成portInfo
  • @TemplateRex 为此,您必须询问 OP。我显示的代码是问题的引用,以显示问题所在。
  • 好吧,你至少可以建议他避免双倍的开销。
  • @TemplateRex 这会改变什么吗?我的意思是我可以在这里看到它是如何成为 const w/o 问题的,但这有什么更好的呢?关于这个副本,我尝试创建指针并检查它是否等于 serialPortInfo 指针(现在不是指针),与 (*serialPortInfo != portInfo);我真的不认为这有什么不同。
  • @smsware 我认为使用for(auto const&amp; element : range) 总是比使用for(auto const : range) 更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
  • 2012-10-24
  • 2015-06-22
  • 2013-07-03
  • 2021-08-25
  • 1970-01-01
相关资源
最近更新 更多