跟着动手,知行泛型编程
实现一个“真正”的泛型Stack
接着上一章的内容继续,上一张章节我们实现类一个“伪泛型”Stack, 它支持c/c++内置类型,如float,double,short等,自定义的类型,入栈数据本身进行了内存开辟等,则显得力不从心,发生了内存泄漏,如:
char* stringNames[] = {"ali","bob","peter"};
//push
for(int i = 0; i < 3; i++){
char* copy = strdup(stringNames[i]);//strdup内部会调用malloc开辟内存,需要调用free
stackObj.GenericStackPush(©);
}
//pop
char* name;
for(int i = 0; i < 1; i++){//出栈一次,只释放类最后一个数据开辟的内存空间
stackObj.GenericStackPop(&name);
printf("pop: %s\n",name);
free(name);
}
对于上述代码,入栈、出栈次数不想等,则会造成内存泄漏!如何解决该问题?
关键点
- 自定义freeFun,该freeFun作为参数传入构造函数
- 析构函数判断Stack当前栈长度并进行自动析构
实现
- GenericStack.h定义
class GenericStack{
public:
int m_nLogicLen;
int m_nAssignLen;
void* m_pElementBuffer;
int m_nElementSize;
void (*m_fFreeFun)(void*);//新增:函数指针,用于释放入栈时产生的内存拷贝
public:
GenericStack(int elementSize, void (*FreeFun)(void*));//新增FreeFun参数
~GenericStack();
public:
bool GenericStackPush(void* elementBuffer);
bool GenericStackPop(void* elementBuffer);
private:
bool GenericStackGrow();
};
- GenericStack.cpp 新增成员函数实现
/*
* @brief 构造函数
* @elementSize 栈中存放的元素的字节长度
* @FreeFun 函数指针,自定义的freeFun函数
*/
GenericStack::GenericStack(int elementSize,void (*FreeFun)(void*)){
this->m_nLogicLen = 0;
this->m_nAssignLen = 4;
this->m_nElementSize = elementSize;
this->m_pElementBuffer = malloc(this->m_nAssignLen * this->m_nElementSize);
this->m_fFreeFun = FreeFun; //新增
assert(this->m_pElementBuffer != NULL);
}
/*
* @brief 析构函数,析构时自动判断队列是否为空,不为空调用型自定义freeFun进行内存释放
*/
GenericStack::~GenericStack(){
if( this->m_fFreeFun != NULL){ //当用户自定义freeFun时进入
for(int i = 0; i < this->m_nLogicLen; i++){
char* address = (char*)this->m_pElementBuffer + i * this->m_nElementSize;
this->m_fFreeFun(address);
}
}
free(this->m_pElementBuffer);
}
- 调用示范
//自定义的freeFun
void StringFree(void* vp){
char* address = *(char**)vp;
printf("free string: %s\n",address);
free( address );
}
int main(){
GenericStack stackObj(sizeof(char*), StringFree); //传入自定义freeFun
char* stringNames[] = {"ali","bob","peter"};
//push
for(int i = 0; i < 3; i++){
char* copy = strdup(stringNames[i]);//strdup内部会调用malloc开辟内存,所以要调用free,这样来模拟需要申请内存空间的stack对象
stackObj.GenericStackPush(©);
}
//pop
char* name;
for(int i = 0; i < 1; i++){//以上使用了malloc这里要对应free
stackObj.GenericStackPop(&name);
printf("pop: %s\n",name);
free(name);
}
return 1;
}
该程序运行完成后,析构函数会调用两次StringFree函数,用于释放入栈所申请的内存空间,这样一个真正意义上的泛型Stack就实现完成了!
到此,整个泛型Stack章节到此就结束了,欢迎小伙伴么多多交流!
推荐一首歌曲, 林志炫大叔,我是歌手我最喜欢的一首歌:没离开过