在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
之前没有接触过 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 起来也很蛋疼,通过长时间的分析和总结才能得到正确的结果。
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论