界面编程中,我比较关心GDI或GDI+对象的创建与销毁。生怕一个逻辑处理不好,就造成了内存泄漏。以前我用传统的delete操作来销毁GDI+对象,但发现编程实现效果不太好,总让人战战兢兢,而且逻辑比较复杂。
如下面这几段代码,我需要时时take care我的Bitmap指针是否是空,是否需要进行销毁:
1. 声明一个Bitmap指针,并需初始化为NULL:
Bitmap* m_bmpProg; // The progress bar canvas.
m_bmpProg = NULL;
2. 动态创建Bitmap内存时,需要先检查之前的内存是否释放掉了:
// Create canvas.
if (m_bmpProg != NULL)
{
delete m_bmpProg;
m_bmpProg = NULL;
}
CRect rcClient;
GetClientRect(&rcClient);
m_bmpProg = new Bitmap(rcClient.Width(), rcClient.Height());
Graphics g(m_bmpProg);
3. 当我的类执行析构函数时,也得检查Bitmap是否被释放掉了。
~CStripeProgress()
{
DeleteCriticalSection(&m_Lock);
if (m_bmpProg != NULL)
{
delete m_bmpProg;
m_bmpProg = NULL;
}
}
4. 如果我的代码里其他地方,需要再次创建Bitmap,那么我还将再一次重复这么个痛苦的过程。我这里还没加入异常判断,如果加入异常判读,那么情况将更加复杂。
使用auto_ptr来管理GDI+对象:
如果使用auto_ptr来管理GDI+对象,事情就变得简单多了。
首先,定义一个Bitmap类型的auto_ptr:
typedef auto_ptr<Bitmap> AUTO_BITMAP; // Auto dispose Bitmap.
AUTO_BITMAP m_bmpCanvas; // The canvas for drawing background image and text.
其次,需要初始化吗?答案是:不要写初始化的代码啦,因为auto_ptr在默认情况下就是NULL型的。
让我们来创建一个Bitmap指针,如下代码,是不是很简单?而且你也不用检查原来的指针是否为空,是否需要释放内存。
m_bmpCanvas = AUTO_BITMAP( newBitmap(rcClient.Width(), rcClient.Height()) );
那我们还需要关心类析构时的问题吗?也不用了,auto_ptr会自动在内析构时,执行内存释放动作。
最后,如果要使用auto_ptr里的Bitmap指针,可以直接使用get函数来获取,如下面进行的绘制,就使用了get函数:
void DoPaint(Graphics& g)
{
EnterCriticalSection(&m_Lock);
if (m_bmpCanvas.get() != NULL)
{
g.DrawImage(m_bmpCanvas.get(), 0, 0);
}
LeaveCriticalSection(&m_Lock);
}
使用auto_ptr需要注意的地方:
1. auto_ptr之间不能共享所有权,因为当执行赋值操作后,右值会进行销毁,那么左值指向的是一个已被销毁的指针。
2. 当用函数传递auto_ptr指针时,需要用auto_ptr_ref来声明传递的参数类型,而不是通常的传值或传地址的方式。
一个免费例子工程,CCustomButton自定义按钮里使用了auto_ptr:http://blog.csdn.net/renstarone/article/details/11177051