前几天上网无意中看到一段程序,可以在VC的debug模式下面通过提取动态分配的内存前面的cookie得到具体分配了多少内存。以前我也想通过cookie来提取这个信息,但当时逐字节分析的,理不出头绪来
int i = *(int*)( (char*)p - 4 * sizeof( int ) );
当然这不具有通用性,在release模式下就不行了。
然后为它构造一个模板函数,用起来方便一点
template<typename T>
int getMemSize(T p)
{
int i = *(int*)( (char*)p - 4 * sizeof( int ) );
return i;
}
执行这段代码,这一直是我想干的。
int *p = 0;
p = new int[0];
cout<<getMemSize(p)<<endl;
本来期望输出1,因为lippman在《深度探索C++对象模型》上讲到了new的一种实现
extern void* operator new(size_t size)
{
if(size == 0)
size = 1;
……
}
如果传进去的size是0,那么size会自动设为1。解释的原因是:每一次对new的调用都必须返回一个独一无二的指针,解决该问题的传统方法是传回一个指针,指向一个默认为1byte的内存块。
但上面的语句输出的是0,p实际上分配的是零个内存单元。然后执行
cout<<(int)p<<endl;
这句,可以发现p实际上是一个指向了一个有效的内存地址。
在争论面前唯一能依赖的就只有标准了。2003的标准上这样写到:
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
在size为0的时候将分配一个没有元素的数组。看来输出0是正确的。<<深>>离出版到现在,已经10年了,或许这里已经发生了变迁。
但还有两个疑问,我猜测这里的p指向的地址应该是cookie的最后一个内存单元的下一内存单元,那么这样就应该可以得到一个独一无二的地址,那么当年为什么会单独分配一个lbyte的单元出来?
这种零元素数组有什么用?
另外在MFC中还使用了另外一种零元素数组。
class A
{
public:
static int a;
static int b[0];
static int c;
};
int A::a;
int A::b[];
int A::c;
int main()
{
cout<<(int)(&A::a)<<endl;
cout<<(int)(&A::b)<<endl;
cout<<(int)(&A::c)<<endl;
}
这里a和b的地址是相同的(如果你把b中的元素个改为一个大于0的数,就不相同了,前提是a,b,c在内存中是连续存放的,但没有理由让它们不连续存放: ) ),说明b的确是一个零元素的数组。
在MFC的消息映射表中
static const AFX_MSGMAP_ENTRY _messageEntries[],
如果你没有定义消息映射,那么就为空
如果要添加消息映射项,可以像
int A::b[] = {1,2};
这样添加就行了;