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 起來也很蛋疼,通過長時間的分析和總結才能得到正確的結果。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM