1.内存泄露问题
尽管内存泄露的原理和解决办法很简单,但是还是有很多人会不自觉的写出内存泄露的程序来,尽管有时候他们的程序并没有运行足够的时间来让他们或客户发现问题,但是了解如何有效的避免内存泄露总是不错的。
一般来说,内存泄露主要是由于申请了相应的资源,但是使用它以后并没有释放。如果只是简单地程序,那很容易避免内存泄露的问题,但是如果,在一个程序中同一个指针p指向的内存区在不同函数间不停的申请和释放,天知道最后p指向的内存是不是被释放了(尽管有时候,少部分狂热分子会拨开层层迷雾去一探究竟,但这是不必要的)。那么如何来解决这个问题呢。
首先,这里用C++来做示例,我们来看一看自己申请的内存区
假设定义 char *p ;
然后p = new char[5] ;
。。。
。。。若干个释放和申请。。。
。。。
现在p指向的内存释放了吗?
有人说,管他三七二十一,再释放一下delete [] p ;
这样显然是不行的,若p巧合没有释放还好,若p已经释放了那就会出问题,这时的指针即所谓的“野指针”是无效的
正确的做法是先对指针做个初始化,p=NULL;(顺便提一句,对于任何变量都做初始化是个不错的主意,他们并占不了什么执行时间,但是却能够带来意想不到的作用,避免很多的错误)
然后在需要释放内存的地方如下处理
if (NULL != p)
{
delete [] p ;
p = NULL ;
}
记住,一旦释放了指针以后,立刻将指针指向NULL,防止“野指针”的出现
当然若程序要多次申请资源,如下处理
if (NULL == p)
{
p = new char[5] ;
}
然后,
然而很多由系统定义的资源分配,如windows的HANDLE,MIL的MIL_ID,Pylon的PYLON_DEVICE_HANDLE
等等,有时候你并不知道他们是不是指针,是否可以用NULL来初始化标志,以及在使用过程中是否会出现值为NULL的情况,这时候用NULL来标识他们是否已经分配或释放会不可靠(其实HANDLE是可行的,他是指向指针的指针,细节此处不详述)。
对于这种情况,有两种办法,一看他的说明,了解其错误分配时的返回值,如HANDLE为NULL,MIL_ID为M_NULL,将上述p例子中的NULL换成相应的错误返回值即可;二倘若没有指名返回值,如PYLON_DEVICE_HANDLE
,那么可以设定一个和该变量相关的标志变量来指明该资源是否已经分配。
2.资源阻塞
打我们用OpenFile打开文件,当指定OF_SHARE_DENY_READ属性时,那么两个进程就不能同时读取这个文件的内容,我称这种状况为资源阻塞。对于资源阻塞的方式可以猜想:1.在打开该文件的同时,再建立建立一个文件记录相关打开和操作信息,如Access(甚至两个线程不允许同时访问同一个文件)和Word,2.在该文件中有特定的标志位段来记录文件打开关闭的信息。
在打开相机操作和打开数据流抓取对象后,再打开相机或数据流抓取对象会出错;意外退出程序若没有做好相关的清理工作,再打开相机或数据流抓取对象也会出错。猜想相机在连接上电脑以后,会自动建立一个文件记录文件打开,关闭和操作相关的信息。打开相机后此时再打开相机时,检测相机相关标识发现已经打开了相机就报错;程序意外出错,退出程序时若没有将相关的标志位置原来正确时的值,再打开程序时检查相关的标志位仍然是错误的,这个显然是不对的。那么解决在打不开相机呢,很简单,此时可以将相机拔下再重插,让相关标志复位即可。如何避免这个问题呢,其实还是和防止内存泄露一样,设置一个标志变量,在打开和意外程序终止时检验相关标志位,做好清理工作。这样才能保证程序的完整性和好的鲁棒性。
3.类和回调函数
由于在类中创建一个线程时要指定回调函数的地址,这时候有两种办法:一是指定一个全局的函数,二是指定类的static函数,但是如果我们想在static函数中访问非static成员变量是个问题,可以如下来解决
Thread.h
#ifndef THREAD_H_H
#define THREAD_H_H
class Thread
{
public:
HANDLE m_hThread ;
int m_num ;
Thread() ;
~Thread() ;
void Create() ;
static DWORD WINAPI ThreadProc(LPVOID lpParameter);
int PrintNum() ;
};
#endif
Thread.cpp
#include
using namespace std;
#include
#include "Thread.h"
Thread::Thread()
{
m_num = 80 ;
}
Thread::~Thread()
{
}
void Thread::Create()
{
::CreateThread(NULL, 0, ThreadProc, LPVOID(this), 0, NULL) ;
}
/*在类中static静态函数属于类,不属于哪个对象,
故调用该函数时不会传进this指针,即默认访问不了非static
变量,这里模拟传进this指针可以使用对象的非static静态变量*/
DWORD WINAPI Thread::ThreadProc( LPVOID lpParameter )
{
Thread * This = (Thread *)lpParameter ;
return This->PrintNum() ;
}
int Thread::PrintNum()
{
cout << "Num的值为" << m_num << endl ;
return 0 ;
}
#include
using namespace std;
#include
#include "Thread.h"
int main()
{
Thread test ;
test.Create() ;
Sleep(10) ; //让副线程运行
return 0 ;
}
执行结果为