不当使用memset函数带来的麻烦问题
来源:互联网 发布:地球只有一个人 知乎 编辑:程序博客网 时间:2024/05/30 07:12
通常在C的编程中,我们经常使用memset函数将一块连续的内存区域清零或设置为其它指定的值,最近在移植一段java代码到C++的时候,不当使用memset函数花费了我几个小时的调试时间。考试大提示: 对于虚函数的底层机制很多资料都有较详细阐述,这次的调试感触颇深。
先来看一段代码,在继承的类Advance之中,有很多属性字段,Examda希望将其清成0或NULL,于是在构造函数中Examda通过memset将当前类的所有属性置0。
class Base{
public:
virtual void kickoff() = 0;
};
class Advance:public Base{
public:
Advance(){
memset(this, 0, sizeof(Advance));
}
void kickoff(){
count++;
//... do something else;
}
private:
int attr1, attr2;
char* label;
int count;
//... other attributes, they should be initiated to 0 or NULL at beginning.
};
int _tmain(int argc, _TCHAR* argv[])
{
Base* ptr = new Advance();
ptr->kickoff();
return 0;
}
这样看似能正常运行,但运行程序时,你会发现类似于下面的错误:
TestVirtual.exe 中的 0x00415390 处未处理的异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突
同时断点停留在ptr->kickoff()处,从错误提示我们可以得知无法调用kickoff方法,这个方法的指针没有被正确初始化,但为什么呢?
指出问题之前,先看看这段文献上的关于虚函数机制的说明:
函数赖以生存的底层机制:vptr + vtable。虚函数的运行时实现采用了VPTR/VTBL的形式,这项技术的基础:
①编译器在后台为每个包含虚函数的类产生一个静态函数指针数组(虚函数表),在这个类或者它的基类中定义的每一个虚函数都有一个相应的函数指针。
②每个包含虚函数的类的每一个实例包含一个不可见的数据成员vptr(虚函数指针),这个指针被构造函数自动初始化,指向类的vtbl(虚函数表)
③当客户调用虚函数的时候,编译器产生代码反指向到vptr,索引到vtbl中,然后在指定的位置上找到函数指针,并发出调用。
这里的问题,就出在
memset(this, 0, sizeof(Advance));
上面,虚函数指针应该在进入构造函数赋值体之前自动初始化的,而memset却又将已经初始化好的指针清0了,这就是为什么会产生上面的访问零址的错误。将上面的memset语句去除程序就可以正常运行了。
所以,从上面的问题中,我们可以看出在构造函数体内调用memset将整个对象清0是很有风险的,当没有虚函数的时候上面程序可以正常运行(可以试着将Base类的纯虚函数声明改成非虚函数再运行程序)。初始化类的属性对象时,比较稳妥的办法还是手动逐个进行初使化。
- 不当使用memset函数带来的麻烦问题
- 关于C++ memset函数使用的问题
- DirectX9带来的麻烦
- 内码带来的麻烦
- StrPCopy带来的麻烦
- switch带来的麻烦
- DontDestroyOnLoad带来的麻烦
- C语言指针使用不当带来的内存不可读
- memset函数的使用
- memset函数的使用
- memset()的函数使用
- memset()函数的使用
- memset函数的使用
- memset函数的使用
- memset 函数 的使用
- memset函数的使用
- memset的使用问题
- 前车之鉴--使用ASSERT可能会给你带来的麻烦
- 我常去的编程技术网站
- 更改Outlook邮件存放位置
- DFB的焦点切换
- (C++)一个愚蠢的错误
- C++中慎用memset初始化struct
- 不当使用memset函数带来的麻烦问题
- JQuery学习日志一(验证用户名是否重复AJAX)
- nginx + tomcat 集群配置详解, 实现负载均衡 URLRewrite Session复制
- Oracle下导出某用户所有表的方法(备份)
- 在Oracle中导出、导入dmp数据库文件
- 我认知的acm
- 基于51单片机的简单交通灯程序
- 我想找合作伙伴~用java技术搭建门户网站~
- TCallBack