我们知道,使用C++智能指针,可以省去我们在申请内存后需要释放对应内存的操作。比如,定义一个int型的shared_ptr并申请一块内存shared_ptr(int) pint(new int),如果给pint重新赋值,或者出pint的作用域,那么,pint原来指向的内存会自动释放,而不需要我们调用delete操作符做释放操作。
不过,上述便利的前提是,申请的内存是基本数据类型,或者定义了析构函数并在析构函数中释放相关资源的类类型或结构体类型。除此,一些例外情况我们在运用智能指针时需要注意。某些第三方库,申请相关资源后,需要用其专用的API释放内存。
下面的例子是正则表达式的API运用于C++中。new操作符申请资源后,需要用regfree释放内存,否则会出现内存泄漏。测试代码如下:
#include <iostream>
#include <deque>
#include <cstdlib>
#include <string>
#include <stdio.h>
#include <regex.h>
#include <boost/smart_ptr.hpp>
using namespace boost;
using namespace std;
int main(int argc, char* argv[])
{
shared_ptr<regex_t> spRegx;
int status, i;
regmatch_t pmatch[1];
const size_t nmatch =1;
const char * pattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*.\\w+([-.]\\w+)*$";
char * buf = "david19842003@gmail.com";
cout<<"mem leak test"<<endl;
i = 0;
while (1)
{
shared_ptr<regex_t> Tmp(new regex_t());
spRegx = Tmp;
i++;
regcomp(spRegx.get(), pattern, REG_EXTENDED);
cout<<"times: "<<i<<endl;
if (1000 == i)
{
cout<<"finish"<<endl;
break;
}
usleep(10*1000);
}
status = regexec(spRegx.get(), buf, nmatch, pmatch, 0);
if (status == REG_NOMATCH)
printf("no match\n");
else if (0 == status)
{
printf("match:\n");
for (i = pmatch[0].rm_so; i < pmatch[0].rm_eo; ++i)
putchar(buf[i]);
printf("\n");
}
regfree(spRegx.get());
while (1)
{
sleep(1);
}
return 0;
}
上述测试程序运行结构如下:
上述测试代码定义了regex_t类型的智能指针,目的是想实现自动释放内存,但是由于没有调用regfree,目的没有达到。观察结果的虚拟内存(VSZ)和物理内存(RSS),都出现了显著增长,说明出现了内存泄漏。
如果要使用智能指针实现内存自动释放,可以对regex_t进行重新封装,将regex_t封装成类或者结构体。在类或结构体中定义析构函数,在析构函数调用regfree API实现内存的释放。如可以利用以下结构体替代上面测试代码的regex_t。
typedef struct regexMap_t
{
regex_t reg;
int compileFlag;
regexMap_t(std::string sReg)
{
int ret = regcomp(®, sReg.c_str(), REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE);
if (ret != 0)
{
compileFlag = 0;
}
else
{
compileFlag = 1;
}
}
~regexMap_t()
{
if (compileFlag)
{
regfree(®);
compileFlag = 0;
}
}
}regexMap_t;
上面是智能指针在regex应用的一个例子,对于需要使用专用API释放内存的其他情形,也需要采取类似的措施。