之前没有接触过 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 = ; 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 = ; 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 起来也很蛋疼,通过长时间的分析和总结才能得到正确的结果。

QT 中使用 c++ 的指针的更多相关文章

  1. Qt中无处不在的d指针为何方神圣

    在研究QCoreApplication类的代码时,无意间弄明白了“d_func()”和“d指针”的来源: class Q_CORE_EXPORT QCoreApplication#ifndef QT_ ...

  2. Qt中窗口退出事件

    窗口右上角的X按键会导致其在不给出任何提示的情况下直接退出, 当点击右上角的x按键时,会触发Qt中的一个事件处理函数:void QWidget::closeEvent ( QCloseEvent * ...

  3. Qt中的ui指针和this指针

    初学qt,对其ui指针和this指针产生疑问,画了个把小时终于搞懂了. 首先看ui指针的定义: 在mainwindow.h中 private: Ui::MainWindow *ui; Ui又是什么? ...

  4. Qt中的Q_D宏和d指针

    _ZTS7QObject 一.Q_D的在文件中的提法 Q_D的设置意在方便地获取私有类指针,文件为qglobal.h.下面的##是宏定义的连字符.假设类名是A,那么A##Private翻译过来就是AP ...

  5. 智能指针类模板(中)——Qt中的智能指针

    Qt中的智能指针-QPointer .当其指向的对象被销毁时,它会被自动置空 .析构时不会自动销毁所指向的对象-QSharedPointer .引用计数型智能指针 .可以被自由的拷贝和赋值 .当引用计 ...

  6. PyQt(Python+Qt)学习随笔:Qt中的部分类型QString、QList和指针、引用在PyQt中的实现方式

    老猿Python博文目录 老猿Python博客地址 在我们查阅Qt的文档资料时,可以看到Qt中的链表使用的是QList,字符串使用的是QString,但老猿在测试时发现这两个类型PyQt不支持,无法找 ...

  7. Qt 中使用Singleton模式需小心

    在qt中,使用Singleton模式时一定要小心.因为Singleton模式中使用的是静态对象,静态对象是直到程序结束才被释放的,然而,一旦把该静态对象纳入了Qt的父子对象体系,就会导致不明确的行为. ...

  8. qt中ui的 使用介绍

    1.什么是ui?ui通常是用Qt 设计师设计出来的界面文件的后缀.通常情况下ui是一个指向这个界面类的指针.ui-> 一般就是用来访问这个界面类里面的控件.例如你的ui文件里有一个叫okButt ...

  9. Qt中sizeof

    class a{ int d; // virtual void ssss(); }; qDebug() <<sizeof(a) << sizeof(int) << ...

随机推荐

  1. webpack+react+redux+es6开发模式---续

    一.前言 之前介绍了webpack+react+redux+es6开发模式 ,这个项目对于一个独立的功能节点来说是没有问题的.假如伴随着源源不断的需求,前段项目会涌现出更多的功能节点,需要独立部署运行 ...

  2. 老司机教你下载tumblr上视频和图片的正确姿势

    本文面向初学者. 很多同学问我:“我非常想学Python编程,但是找不到兴趣点”. 还有的同学呢,找到了很好的兴趣点,但是无从下手,“玄魂老师,我想下载tumblr上的视频, 怎么下载,Python能 ...

  3. HDU4403(暴搜)

    A very hard Aoshu problem Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  4. RedisRepository分享和纠错

    .mytitle { background: #2B6695; color: white; font-family: "微软雅黑", "宋体", "黑 ...

  5. DevExpress控件之RepositoryItemComboBox

    RepositoryItemComboBox在嵌入到GridView后,如何获取当前所选的Item? 直接代码: ((RepositoryItemComboBox)gridView.Columns[& ...

  6. Nginx反向代理、CORS、JSONP等跨域请求解决方法总结

    由于 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制.即会出现跨域请求禁止. 通俗一点说就是如果存在协议.域名.端口或者子域名不同服务端,或一者为IP地址,一者为 ...

  7. Java中boolean类型到底占用多少字节

    虽然 Java 虚拟机定义了 boolean 这种数据类型,但是只对它提供了非常有限的支持.在 Java 虚拟机中没有任何供 boolean 值专用的字节码指令,在 Java 语言之中涉及到 bool ...

  8. TPS及计算方法

    个事务,TPS为6 / 60s = 0.10 TPS.同时我们会知道事务的响应时间(或节拍),以此例,60秒完成6个事务也同时代表每个事务的响应时间或节拍为10秒.   利特尔法则  (Little' ...

  9. Python学习--17 进程和线程

    线程是最小的执行单元,而进程由至少一个线程组成.如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间. 进程 fork调用 通过fork()系统调用,就可以生成一个子进程 ...

  10. UINavigationController实现全屏滑动返回功能

    说明: UINavigationController默认在push出的控制器中都有边沿滑动返回功能,但是只能从屏幕左边滑才能返回,若从屏幕中间画并没有效果.下面实现全屏滑动功能. 探究: 系统默认能够 ...