先上代码和结论:
class A{...................};
int main()
A* pA = malloc(sizeof(A));
memset(pA,0,sizeof(A));
............
printf("hello world!");
}
大致伪代码可以这么写了。
这里看,就是使用了C的内存申请方式来初始化了一个C++的类A的实例。这样的做法,现在可能不常见,但是在比较老旧的框架或者代码中依然存在。然后笔者经历了一个因为这种方式导致的诡异bug。
我们先讨论一下,照C++的模式来思考,这里可能存在的问题。
1,首先看sizeof(A)是否可能为0?
不可能,因为C++标准制定了,当A即使没有任何成员变量时,sizeof(A)==1。否则sizeof(A)==0的话会导致无成员变量的类无法申请内存(因为成员函数不占内存,至于成员函数和成员变量占据内存的差异,这里简单说就是,成员函数不占据任何类成员空间,因为他们所处的域不同,成员函数处于代码段,而成员变量一般处于堆栈数据段)。所以即使是一个有1000个成员方法没有任何成员变量的类,他的size依然是1。
2,照1的结论来看,假设对于类,仅有类成员变量占据空间的情况下,这里应该是不存在问题的。代码与数据分离,数据又被格式化为0。看上去很ok。但是实际上C++还有另外一种占据类内存空间的对象,举个例,比如虚表指针。
虚表:
https://www.cnblogs.com/hushpa/p/5707475.html
https://www.cnblogs.com/vipchenwei/p/7466018.html?utm_source=debugrun&utm_medium=referral
https://blog.csdn.net/u014744118/article/details/51020480(这个不知道被面试题考过多少次,现在还在考)
这三篇文章看完看懂的话,就会理解上面这个代码在某些情况下,就会出现问题。
在类存在虚函数的情况下,类会有一张虚表(除非你ATL_NO_VTABLE,)这样,在C的初始化模式下,会将虚表的头指针指向0地址,这样就会造成非法指针访问。因为虚函数是根据虚表头进行索引找到虚函数入口地址,一旦虚表头置0,那就是0是第一个虚函数入口地址,发生虚函数访问或者多态,立马崩。
笔者在对应的出错地看到了一个 : 有效指针->有效方法的访问模式,然后经过debug调试查找找到这个bug,中间涉及C++的内存模型,还有C++初始化和C模式的malloc初始化方式的区别,除了new之外,虚表还有其他很多因素都是malloc无法替代的。
Warning!