实现思路
最近在看Redis源代码,发现了许多自己不知道的C语言的书写方式,这些写法可以实现许多结构。
CXX
使用泛型提供了容器,但是C语言中不允许将数据类型作为参数进行传递,所以我们必须使用另一种方式来实现我们的目的结构。
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
typedef struct listIter {
listNode *next;
int direction;
} listIter;
typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
list *listCreate(void); // 创建
void listRelease(list *list); // 删除
list *listAddNode(list *list, void *value); // 添加
listNode *listSearchKey(list *list, void *key); // 查找
Redis使用这种定义结构实现容器的定义,我们可以看到容器内部的数据使用void *value
去指向,而我们的容器中包含四个函数void *(*dup)(void *ptr)
、void (*free)(void *ptr)
、int (*match)(void *ptr, void *key)
、void (*print)(void *ptr)
。每当我们需要操作容器内部的数据value
时,我们就调用这个函数指针对应的方法进行操作,这样就实现了不同的数据类型能够达到不同的操作的方式。
其中我们看到我们给出了free
函数,因为我们释放链表节点的同时我们需要释放其value *
所指向内容的地址空间,然而这个结构可能还引用了其他的结构,所以我们必须手动提供一个free
函数,来指导链表正确释放所指向的空间。
从中我们也能看到,CPP中析构函数的动态顺序也符合这个顺序,先析构子成员再析构自身。
完整示例