问题目录
前言
在现在很多公司面试中(中大型公司),基本都会问到你最近遇到的什么难的问题!怎么处理解决的,以及问题怎么分析的相关问题。。。。。。其实在没有准备的情况下,这个问题是比较麻烦的,总不能说我平时都是写业务的,遇到的问题都是和项目经理扯皮吧。而且就是以前遇到过很多典型的,或者奇葩的问题一时半会也记不起来啊,更别说问题分析和解决方法了。所以,现在就使用博客记录记录,以防不时之需!
1、debug模式运行正常,relase模式出现异常或者段错误!
推荐文章:https://blog.csdn.net/u010521560/article/details/78710421
首先两者区别:
Debug通常称为调试版本,通过一系列编译选项的配合,编译的结果通常包含调试信息,而且不做任何优化,为开发人员提供强大的应用程序调试能力。
而Release通常称为发布版本,是为用户使用的,一般客户不允许在发布版本上进行调试。所以不保存调试信息,同时,它往往进行了各种优化,以期达到代码最小和速度最优。为用户的使用提供便利。
我出现的错误是段错误问题,内存溢出导致的。具体为什么debug调试没有出现问题?
猜测是因为debug编译的时候不会对代码进行优化,导致生成的变量内存是连续的,当前面的变量内存访问溢出的时候,会操作后面的变量内存,所以不一定会 出现段错误问题。
而relase模式则对编译进行了优化处理,所以创建的内存不一定是连续的内存,当前面的内存访问溢出后不一定就是操作后面变量的内存,所以可能导致段错误问题。内存操作导致段错误的原因有如下:
1.访问不存在的内存地址 (int *ptr = NULL;*ptr = 0;)
2.访问系统保护的内存地址 (int *ptr = (int *)0;*ptr = 100;)
3.访问只读的内存地址
4.栈溢出
2、父类和子类不能跨线程的问题
运行时候报错如下:
QObject: Cannot create children for a parent that is in a different
thread (Parent is QSerialPort(0x17b1ce60), parent’s thread is
QThread(0x17b1c220), current thread is TxRxThread(0xbbfdc4)
这个问题的意思是父类和子类所处的 线程不一致!
为什么父类和子类不能跨线程,应该是线程安全问题,类中成员数据的写入不存在线程锁,如果两个线程同时写入,可能导致数据问题,以上说法可能存在问题,纯属个人推测。
3、qt编译静态断言
错误如下图:
这种情况大概率是信号槽参数不对等造成的,即绑定的信号槽,信号少了参数,或者槽函数多了参数。
qt编译的时候对信号槽都会进行检测,查看语法是否规范,提前发现问题,避免程序运行过程中才崩溃卡死。
信号槽参数的原则:
- 槽函数的参数一定不能多于信号的参数;
- 槽函数的所有参数类型必须与信号的参数类型保持一致;
- 还有在Qt中的信号槽机制中,信号能携带的参数最多不超过6个;
- 信号槽函数无法重载,否则编译不通过,毕竟谁知道你要绑定的是哪个信号槽。
补充内容:
- Qt4的信号槽连接方式是基于字符串的,只能在运行时进行检测。
- 而Qt5中保留了Qt4的信号槽连接方式,同样也提供了一种新的信号槽连接方式,即函数指针连接,这样在编译的时候就进行了检测,从而提高了安全性,这也是官方推荐使用的连接方式。
- 与QML连接信号槽也只能使用Qt4的方法。
4、sqlite数据库备份删除和恢复后,占用的磁盘空间越来越大的问题。
问题图解:
在上图中,数据库备份为数据包后,删除了大部分数据(保留了出厂设置数据),数据库文件的大小还是那样,没有变。
恢复数据操作,考虑到效率,我们的操作是直接追加,而不会对相同的数据进行判断过滤而添加,所以会造成占用空间的直接增加
问题原因:
在sqlite中,从Sqlite删除数据后,空出的磁盘空间将被添加到一个内在的”空闲列表”中,用于存储你下次插入的数据存储,这些磁盘空间并没有被使用,但也不向操作系统返回这些磁盘空间。
解决方法:
方法一: 在数据删除后,执行VACUUM命令。
直接执行此VACUUM命令的方法只对删除表格有效,如果使用where条件语句删除的数据,运行该命令则无效。摸索出来的结果,原因目前未知。
所以我的操作如下:
bool Builder::clearStorage(QSqlDatabase &db,QString tabName)
{
#if 0
if(db.transaction()) //启动事务操作
{
QSqlQuery sqlQuery(db);
sqlQuery.exec(QString("create table BUFF_Table as select * from %1").arg(tabName));
sqlQuery.exec(QString("DROP TABLE %1").arg(tabName));
sqlQuery.exec(QString("ALTER TABLE BUFF_Table RENAME TO %1").arg(tabName));
sqlQuery.exec(QString("VACUUM"));
if(!db.commit()) //提交
{
if(!db.rollback()) //回滚
return false; //回滚错误才表示操作失败
}
Query query = exec(QString("VACUUM"),QSqlDatabase::database(connectionName));
}
#else
Query query = exec(QString("create table BUFF_Table as select * from %1").arg(tabName),db);
query.exec(QString("DROP TABLE %1").arg(tabName));
query.exec(QString("ALTER TABLE BUFF_Table RENAME TO %1").arg(tabName));
query.exec(QString("VACUUM"));
#endif
return true;
}
经过测试,上面的事务操作,最后的VACUUM命令执行无效,原因未明。
推荐使用该方式手动执行VACUUM命令,去压缩Sqlite数据库文件的大小。
方法二: 在数据库文件建成中,将auto_vacuum设置成“1”。
只有在数据库中未建任何表时才能改变auto-vacuum标记。试图在已有表的情况下修改不会导致报错。
当开启auto-vacuum,当提交一个从数据库中删除除数据的事物时,数据库文件自动收缩。
数据库会在内部存储一些信息以便支持这一功能,这使得数据库文件比不开启该选项时稍微大一些。
此方法为网上找到的,未经过自测。
5、qt信号槽未绑定槽函数对象类指针,导致运行时出现段错误。
问题描述:
在qt信号槽绑定中,参数未传入槽函数所在类指针,但是槽函数中又使用的了类的资源,当类被释放后,该信号槽不会自动解绑(因为你没有传入槽函数所在的对象的指针),这就会导致信号发送后,槽函数还是会执行,且调用被释放类的资源,从而导致段错误。
错误使用示范:
connect(&A, &A::sig_UpdateData,[=](){
B->reset();
}
A、B类都存在的时候,connect绑定成功。因为B的指针未添加到connect函数中,所以后面B类被释放后,不会自动disconnect,发送信号的时候,槽函数还是会执行,而且槽函数中调用了B的方法,从而导致段错误。
此问题比较隐蔽且出乎意料,加上业务代码后更加难查。上面问题解决方法如下:
connect(&A, &A::sig_UpdateData,&B,[=](){
B->reset();
}
添加B对象指针即可,当B对象释放的时候,代码会自动执行disconnect函数解绑。