通常在C编程中我们经常使用mem将块连续内存区域清零或设置为其它指定值最近在移植段java代码到C时候不当使用mem花费了我几个小时调试时间对于虚底层机制很多资料都有较详细阐述但对我个人而言这次调试让我感触颇深
先来看段代码在继承类Advance的中有很多属性字段我希望将其清成0或NULL于是在构造中我通过mem将当前类所有属性置0
Base{
public:
virtual void kickoff = 0;
};
Advance:public Base{
public:
Advance{
mem(this, 0, (Advance));
}
void kickoff{
count;
//... do something ;
}
private:
attr1, attr2;
char* label;
count;
//... other attributes, they should be initiated to 0 or NULL at beginning.
};
_t( argc, _TCHAR* argv)
{
Base* ptr = Advance;
ptr->kickoff;
0;
}
这样看似能正常运行但运行时你会发现类似于下面:
TestVirtual.exe 中 0x00415390 处未处理异常: 0xC0000005: 读取位置 0x00000000 时发生访问冲突
同时断点停留在ptr->kickoff处从提示我们可以得知无法kickoff思路方法这个思路方法指针没有被正确化但为什么呢?
指出问题的前先看看这段文献上有关虚机制介绍说明:
赖以生存底层机制:vptr + vtable虚运行时实现采用了VPTR/VTBL形式这项技术基础:
①编译器在后台为每个包含虚类产生个静态指针(虚表)在这个类或者它基类中定义每个虚都有个相应指针
②每个包含虚类每个例子包含个不可见数据成员vptr(虚指针)这个指针被构造自动化指向类vtbl(虚表)
③当客户虚时候编译器产生代码反指向到vptr索引到vtbl中然后在指定位置上找到指针并发出
这里问题就出在
mem(this, 0, (Advance));
上面虚指针应该在进入构造赋值体的前自动化而mem却又将已经化好指针清0了这就是为什么会产生上面访问零址将上面mem语句去除就可以正常运行了
所以从上面问题中我们可以看出在构造体内mem将整个对象清0是很有风险当没有虚时候上面可以正常运行(可以试着将Base类纯虚声明改成非虚再运行)化类属性对象时比较稳妥办法还是手动逐个进行初使化
最新评论