跟着动手,知行泛型编程
实现一个”泛型”的Stack
接着上一篇内容继续,上一篇中实现了一个支持int类型的Stack,接下来将实现一个支持泛型的Stack,我们先假设要现在一个仅支持内置类型的Stack,如:int, float, double, short等。
- 让我们先从头文件的定义开始,直接上代码:GenericStack.h
#include <iostream>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
class GenericStack{
public:
int m_nLogicLen; //栈的实际长度
int m_nAssignLen; //栈分配的空间的长度
void* m_pElementBuffer; //栈中数据的存放空间地址
int m_nElementSize; //新增加的参数,栈中保存的数据的字节长度,如int:4
public:
GenericStack(int elementSize);
~GenericStack();
public:
bool GenericStackPush(void* elementBuffer); //入栈
bool GenericStackPop(void* elementBuffer); //出栈
private:
bool GenericStackGrow();
};
- GenericStack.cpp实现:
/*
* @brief 构造函数
* @elementSize 栈中存放的元素的字节长度
*/
GenericStack::GenericStack(int elementSize){
this->m_nLogicLen = 0;
this->m_nAssignLen = 4;
this->m_nElementSize = elementSize;
this->m_pElementBuffer = malloc(this->m_nAssignLen * this->m_nElementSize);
assert(this->m_pElementBuffer != NULL);
}
/*
* @brief 析构函数
*/
GenericStack::~GenericStack(){
free(this->m_pElementBuffer);
}
/*
* @brief 入栈
* @elementBuffer 入栈元素的地址
*/
bool GenericStack::GenericStackPush(void* elementBuffer){
if( this->m_nLogicLen == this->m_nAssignLen){
GenericStackGrow();
}
void* target = (char*)this->m_pElementBuffer + this->m_nLogicLen * this->m_nElementSize;
memcpy(target, elementBuffer, this->m_nElementSize);
this->m_nLogicLen ++;
return true;
}
/*
* @brief 出栈
* @elementBuffer 出栈元素的地址
*/
bool GenericStack::GenericStackPop(void* elementBuffer){
void* target = (char*)this->m_pElementBuffer + (this->m_nLogicLen - 1) * this->m_nElementSize;
memcpy(elementBuffer, target, this->m_nElementSize);
this->m_nLogicLen --;
return true;
}
/*
* @brief 栈元素空间增长
*/
bool GenericStack::GenericStackGrow(){
assert(this->m_nAssignLen > 0);
this->m_nAssignLen = this->m_nAssignLen * 2;
this->m_pElementBuffer = realloc(this->m_pElementBuffer, this->m_nAssignLen * this->m_nElementSize );
assert( this->m_pElementBuffer != NULL);
return true;
}
现在一个支持内置类型的“泛型”Stack就算实现好了,相比较与上一章所介绍的Stack,支持类更多的内置类型
知识点
- void*指针不可以直接进行+/-,取值等运算,必须要转化为相应的类型指针,比如char*
这样一个简单的“泛型”,就算完成了,可是对于自定义的数据类型,该Stack明显显的心有余而力不足,我来举个例子:
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 < 3; i++){//以上使用了malloc这里要对应free
stackObj.GenericStackPop(&name);
printf("pop: %s\n",name);
free(name);
}
对于上述例子,入栈的数据本身进行了内存开辟,入栈3个数据,出栈3个数据,没有问题,但是当我们的pop出栈部分改成如下代码时:
//pop
char* name;
for(int i = 0; i < 1; i++){//出栈一次,只释放类最后一个数据开辟的内存空间
stackObj.GenericStackPop(&name);
printf("pop: %s\n",name);
free(name);
}
很明显上述代码就会存在内存泄漏问题,如何解决该问题?
关键点:
- 如何自定义专属数据类型的“析构函数”?
带着这个问题,接下来我将实现一个正真意义上的泛型Stack
推荐一首歌,还是一首嘻哈曲风的歌曲,安全着陆的我欲乘风……..