3
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?但这只是我的猜测,也许原因不同......

4

2 回答 2

3

问题是这个循环:

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

该变量portInfo仅在循环内具有其范围,并且仅适用于当前迭代。一旦循环迭代,该变量就会被破坏。使用指向被破坏对象的指针是未定义的行为,并且可能是导致崩溃的原因。

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

于 2014-07-21T11:32:21.533 回答
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直接在方法中使用。

于 2014-07-21T11:37:15.510 回答