遇到的一个内存分配的问题

Freeze_Z 2012-05-28 02:52:11
简单描述下遇到的问题.

主程序是有UI 的程序. QT.
程序启动后会有几个界面和线程开始跑.
其中一个界面的对象中一个定时器和一个QString value.

定时器timeout后, 执行以下:
1.value = SomeClass::getValue(). 此接口返回类型为QString.
之后没有对value写调用的地方.
2.调用一些C接口. 接口中有多次的calloc动作.
3.检查value的值.

异常:
经加打印发现.
计算QString value中的字符串地址. void* p = value.toLocal8Bit().data();
calloc申请的内存地址, 有时候会覆盖到 p 的空间.(发生几率大概为1/10 ~ 1/20).
问题重现的步骤都是 开机. 打印看p的地址及calloc申请的地址. 然后重启.

个人的理解:
QString中存储具体内容的char*空间是的动态申请的, calloc申请动态内存理论上不应该覆盖到这部分内存.
个人猜测的原因:
程序运行时内存被破坏, 导致系统识别p对应的内存为未被占用状态.

已经为这个问题纠结2天.
请问大家有什么想法么.
...全文
279 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
这篇文章可能有些深奥了,毕竟大多数内容来自于<<Inside The C++ Object Model>>
那么就留下一条忠告:
在stl中,以下的代码是错误的
string getName();
char* pTemp = getName().c_str();
getName返回的就是一个临时变量,在把它内部的char指针赋值给pTemp后析构了,这时pTemp就是一个非法地址
确实如C++发明者Bjarne Stroustrup所说,这种情况一般发生在不同类型的相互转换上

在Qt中,类似的代码是这样的
QString getName();
char* pTemp = getName().toAscii().data();
这时pTemp是非法地址

参考 http://blog.csdn.net/wangjiwei2010/article/details/1625704

const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
ssid_previous.toLocal8Bit()产生的临时对象, 已经在这句后销毁啦.

原来是这样.
不懂C++的我写C++程序弱爆啦.

谢谢大家啦.
jdwx 2012-05-28
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]

toLocal8Bit()这个方法的问题,他会创建一个局部QByteArray,你通过void *p去获取到的是QByteArray的地址,并不是QString的地址。出了作用于QByteArray被析构了。
[/Quote]
估计是这个问题,data()返回一个临时对象,p就指向那个临时对象。
先给p分配一块内存,strcpy(p,xxx.toLocal8Bit().data());
这样看看有效果没有。

还有,如果没有禁止自动转换,QString可以自动转换为char*
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
void WelcomeForm::slotWifiScanResult()
{
const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
printf("previous_ssid_str : <%p><%s>.\n", previous_ssid_str, previous_ssid_str);
printf("ssid_previous.toLocal8Bit().data() : <%p><%s>.\n", ssid_previous.toLocal8Bit().data(), ssid_previous.toLocal8Bit().data());

ap_info *ap_info_p = wireless_func_p->getSsidInfoByStr(previous_ssid_str);
printf("previous_ssid_str : <%p><%s>.\n", previous_ssid_str, previous_ssid_str);
printf("ssid_previous.toLocal8Bit().data() : <%p><%s>.\n", ssid_previous.toLocal8Bit().data(), ssid_previous.toLocal8Bit().data());
}

previous_ssid_str : <0x45478f0><BRD>.
ssid_previous.toLocal8Bit().data() : <0x45478f0><BRD>.

previous_ssid_str : <0x45478f0><>.
ssid_previous.toLocal8Bit().data() : <0x4610d60><BRD>.

why?
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
ap_info *ap_info_p = wireless_func_p->getSsidInfoByStr(previous_ssid_str);

实际运行结果显示:
wireless_func_p->getSsidInfoByStr调用的过程中, previous_ssid_str对应的字符串的值, 发生改变.
previous_ssid_str进去的时候 打印出 %s , 为 "ABC". 调用其它无关 previous_ssid_str的接口后, 打印出来的结果是"". why?


非常感谢.
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
ap_info *ap_info_p = wireless_func_p->getSsidInfoByStr(previous_ssid_str);

wireless_func_p->getSsidInfoByStr调用的过程中, previous_ssid_str的值为什么可能改变呢?
非常感谢.
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
也就是说,你在里面做 str_ssid++;这样的操作是可以的。。就是地址加下一。
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
地址可变? 你是说在wireless_func_p->getSsidInfoByStr的整个调用过程中, previous_ssid_str地址对应的值可能改变?

刚才一直刷这个帖子呢, 抱歉回的有点慢.
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
谢谢你的解答.

请帮忙看下下段.
void WelcomeForm::slotWifiScanResult()
{
......
const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
ap_info *ap_info_p = wireless_func_p->getSsidInfoByS……
[/Quote]
是的,str_ssid 它的内容在这个函数里面是不能变的。但是它的地址可变。
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
谢谢你的解答.

请帮忙看下下段.
void WelcomeForm::slotWifiScanResult()
{
......
const char* previous_ssid_str = ssid_previous.toLocal8Bit().data();
ap_info *ap_info_p = wireless_func_p->getSsidInfoByStr(previous_ssid_str);
......
}


ap_info* WirelessFunc::getSsidInfoByStr(const char* str_ssid)
{
parseScanResult();
...
return ret_ap_info;
}

在wireless_func_p->getSsidInfoByStr(previous_ssid_str);
这一句中, getSsidInfoByStr, parseScanResult 的整个调用过程中, previous_ssid_str对应的字符串的值应该不变?
是么?
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
QString value 设置成一个if里面的局部变量就可以了。除了if的大括号 就出了作用域了。
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
这个比较像.
我需要验证一下. 另外之前的code怎么将p 传到作用域之外.

xiebin133 2012-05-28
  • 打赏
  • 举报
回复
toLocal8Bit()这个方法的问题,他会创建一个局部QByteArray,你通过void *p去获取到的是QByteArray的地址,并不是QString的地址。出了作用于QByteArray被析构了。
shen_wei 2012-05-28
  • 打赏
  • 举报
回复
理论上该UI对象没有释放的话, value不会被释放, 是么?

是的,只要不释放就一直存在!!

qDebug<< QString;这样debug信息 #include <QDebug>
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
toLocal8Bit()这个的问题,他里面会创建一个QByteArray, 也就是他返回的地址并不是QString的地址,你可以用指针去访问下看看,而是一个局部的QByteArray的地址。
donwmufromdying 2012-05-28
  • 打赏
  • 举报
回复
void* p = value.toLocal8Bit().data();
这个问题挺经典阿! 貌似很多人问过,也很多人回答过。value.toLocal8Bit().data()这个指针是很有问题的!
请不要这么用。要么你自己申请内存后把这个strcpy或者memcpy过去
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]
针对 xiebin133, cnsword的回答. 我重新加debug信息确认一次.

另外, 补充下信息
QString value;
是包含在一个大的UI类中, 该UI类对象是new出来的. 该UI对象在设计上会尽量保留不释放.
理论上该UI对象没有释放的话, value不会被释放, 是么?
[/Quote]
如果QString value是在类中声明的,类是通过new出来的, 类没被delete之前是不会被释放的。
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
针对 xiebin133, cnsword的回答. 我重新加debug信息确认一次.

另外, 补充下信息
QString value;
是包含在一个大的UI类中, 该UI类对象是new出来的. 该UI对象在设计上会尽量保留不释放.
理论上该UI对象没有释放的话, value不会被释放, 是么?
开发者说 2012-05-28
  • 打赏
  • 举报
回复
QString也是有生命周期的,看你的代码value分配在栈上,系统会将它在作用域结束后销毁,它内部的data也就已经被释放了,被其他变量内存覆盖是自然的事情。
Freeze_Z 2012-05-28
  • 打赏
  • 举报
回复
谢谢你的回帖.

贴code有点困难. 相关的贴下来应该在1000行左右.

针对这个问题, 我比较想要个debug的思路, 或者说是这种状况可能发生的原因.
比如, QString的错误使用, 检查QString中值域被free掉的方法, 检查内存误写的方法 等等.
xiebin133 2012-05-28
  • 打赏
  • 举报
回复
void* p = value.toLocal8Bit().data();//QString value是不是个局部变量,如果是的可能出了作用域已经释放,这部分地址又回归了内存,内存就可以在分配出去。
加载更多回复(3)

16,203

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧