QT 中使用 c++ 的指针

之前没有接触过 c++,不过听说 c++ 的指针很坑,直到最近在用 QT / C++ 写一个 Linux Deepin 系统上检测网络流量和网速的小程序时,发现 c++ 的指针用起来真的特别蛋疼。

不过好在花了几个小时最终还是明白了指针的用法。

 

有一段代码的原型大概是这样的:

QList<NetFlowObject>  netflowobj_list;

/** 从 list 列表中找出网卡名为 ifname 的 NetFlowObject 对象 **/
bool getNfoFromList(QString ifname, NetFlowObject &nfo);

其中 NetFlowObject 是自己写的一个类,QList 是 Qt 提供的一个链表。 getNfoFromList 函数返回 boolean 型结果,如果找到相同名称的网卡,返回 true,并将 nfo 设为 QList 中找到的 NetFlowObject 对象。否则返回 false。

那么最开始的想法是通过遍历 QList 找到 NetFlowObject 对象。

bool NetInfo::getNfoFromList(QString ifname,NetFlowObject &nfo) {    //-------- A①

  foreach(NetFlowObject o, netflowobj_list) {              //-------- A②

    if(o.getIfName() == ifname) {  //-------- A③

      nfo = o; return true;

    }

  }

  return false;

}

void NetInfo::someFunction() {
   // 如果找到相同的 nfo 对象,修改它的数据
   NetFlowObject nfo1;
   bool finded = getNfoFromList(ifname, nfo1);              //-------- B① 
   if(finded) {
     nfo1.updateRecvBytes(if_recv_bytes.toInt());
     nfo1.updateTransBytes(if_trans_bytes.toInt());
   }
}

嗯,上面的这段代码很显然没有办法修改 QList 链表中的对象的属性。首先,函数是传值的,也就是说 A① 处函数的参数 nfo 是不会影响 someFunction 里 B① 处的 nfo1 对象的。nfo1 对象的属性改变同样也不会影响 nfo 对象。

通过函数的参数传递的只是 nfo1 对象的一个副本,两个对象之间不会影响。

其次,A②处的 foreach 这个便捷的循环也是提供 QList 对象的一个副本,这样的话,更加没有办法修改找到的 NetFlowObject 对象了。

好吧,这个错误是 c++ 最常见也是最愚蠢的错误,那么想要得到 QList 中的某个 NetFlowObject 对象的引用,函数传递的就不能是 NetFlowObject 对象了,那么就改成 NetFlowObject * 也就是指针吧。另外,将循环改为 for 计数循环。

代码如下

bool NetInfo::getNfoFromList(QString ifname,NetFlowObject *nfo) {
    for(int i = 0; i < netflowobj_list.count(); i++) {
        NetFlowObject o = netflowobj_list[i];
    //        PrintUtil::print(o.getIfName() + "  ===  " + QString::number(o.getLatestRecvBytes()));
        if(o.getIfName() == ifname) {
            *nfo = netflowobj_list[i];  // 将指针所指向的 NetFlowObject 对象修改为 o      -------C①
            return true;
        }
    }
    return false;
}

相应的,

bool finded = getNfoFromList(ifname, &nfo1);

但是这样做,发现修改 nfo1 对象仍然没有效果, QList 中 NetFlowObject 对象的属性依然没有改变。恩没有错,上面代码 C① 处又是传递的副本。

这里要说一下 QList 对象的 at(i) 函数和 QList[i] 数组形式得到的对象是不同的。函数原型为 const T &QList.at(int i) const,也就是不能通过 at() 的返回值对 nfo 对象进行修改,

而数组形式的函数原型是 T &QList::operator[] (int i),也就是用起来和平常的数组没什么太大区别。

 

既然一层引用不能达到效果,那么,函数传递的时候,就传一个 NetFlowObject * 对象的指针,也就是作为 NetFlowObject 对象的指针的引用。(这个指针的指针说起来太绕口了,第二个指针改称引用,不然脑子就浆糊了),贴出最终的代码:

bool NetInfo::getNfoFromList(QString ifname,NetFlowObject **nfo) {
    for(int i = 0; i < netflowobj_list.count(); i++) {
        NetFlowObject o = netflowobj_list[i];
//        PrintUtil::print(o.getIfName() + "  ===  " + QString::number(o.getLatestRecvBytes()));
        if(o.getIfName() == ifname) {
            *nfo = &netflowobj_list[i];  // 将指针所指向的 NetFlowObject 指针修改为 QList 中第 i 个对象的引用
            return true;
        }
    }
    return false;
}

void NetInfo::someFunction() {
        NetFlowObject *nfo;
        bool finded = getNfoFromList(ifname, &nfo);
        if(finded) {
            nfo->updateRecvBytes(if_recv_bytes.toInt());
            nfo->updateTransBytes(if_trans_bytes.toInt());
        }
}    

通过两层引用,最终达到了修改 QList 链表中对象的目的。

感觉还有一种解决方法,就是将函数原型 getNfoFromList 修改成 NetFlowObject * getNfroFromList(QString ifname);

找到相应的对象后直接返回该对象的引用,这样就不用通过函数参数传递两层引用了。

 

--------------------------  思考 -------------------------

引用指针绕的头都晕了,而且这个错误理论上应该属于逻辑错误(编译时不会报错,运行时不会发生异常),但是特喵的就是结果不对,debug 起来也很蛋疼,通过长时间的分析和总结才能得到正确的结果。

 

posted @ 2016-11-07 09:06  brifuture  阅读(5719)  评论(4编辑  收藏  举报