2007年5月17日星期四

关于stack和heap

刚才在看《VC++技术内幕》,关于CDC对象的Constructing和Destroying ,
书中给出了两个代码段,都是CView类的OnLButtonDown函数的实现,第一段
代码在函数结尾处由编译器自动释放了CDC对象,而第二段代码则必须由程序员
给出释放CDC对象的代码,
下面就是这两段代码:
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rect;

CClientDC dc(this); // constructs dc on the stack
dc.GetClipBox(rect); // retrieves the clipping rectangle
}
// dc automatically released
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rect;

CDC* pDC = GetDC(); // a pointer to an internal dc
pDC->GetClipBox(rect); // retrieves the clipping rectangle
ReleaseDC(pDC); // Don't forget this
}
   第一段代码的注释明确告诉了我们,dc是分配在stack上的局部变量,
所以在函数结尾,它就被自动析构(释放)了。而第二段呢,
我认为是在
GetDC()函数里使用了类似new运算符的操作在heap上分配了CDC对象的
内存,再将其地址返回给指针pDC,因此,程序员就必须得为GetDC()
函数擦屁股了。

前段时间看Thinking In C++的时候,就曾经为这个问题疑惑了一阵。
在C++Object被创建时,首先是分配内存,书中也谈到,使用static
storage area,stack,heap都是可以的,显然动态内存分配需要的是
heap(free store),而stack有它的好处,首先是效率高(These
stack-allocation operations are built into the
instruction set of the processor andare efficient.),
其次在stack中分配的内存会被自动释放,为什么呢?这个问题涉
及到编译,这里就看看Windows Glossary的解释:
stack -A region of reserved memory in which applications
store status data such as procedure
and function call
addresses, passed parameters, and sometimes local variables.

一个程序、函数在编译后,
一般是采用栈(stack)的push和pop来
执行的,所谓有进必有出,局部的对象和变量必然会被一个不漏的消灭掉。
而在heap上动态分配内存之后,一般获得的是指针,分配到的内存并没有
进入函数的栈(Stack)内,所以stack也没有责任释放这些内存。
好了,说了这么多,关键还是要在写程序的时候准确判断那些是来自
heap,现在看来,如果一个指针来历不明,那就必须把它当作指向heap的
指针,我们就得准备好擦屁纸了。如果是一个具名的对象,不管它多复杂,
都不用操心了,哈哈。但是也有例外,CView::OnDraw(CDC*pDC)的
这个不需要我们动手,千万不要画蛇添足,惹是生非。

没有评论:

Google