jrtplib允许用户自己管理内存. 默认情况下, 该库会调用运算符new/delete来分配/释放运行过程中需要的内存空间.
这两天研究jrtlib-3.8.2库,原本是研究其rtp/rtcp的实现, 在跟踪代码时,却发现它提供给用户管理内存的接口,设计得非常巧妙, 如教科书般的将C++各种特性展现出来.
这中间主要是两个类:
RTPMemoryManager 这个类是个纯虚类:
- class RTPMemoryManager
- {
- public:
- RTPMemoryManager() { }
- virtual ~RTPMemoryManager() { }
-
- virtual void *AllocateBuffer(size_t numbytes, int memtype) = 0;
-
- virtual void FreeBuffer(void *buffer) = 0;
- };
最主要的是这个类有自己的new/delete以及new[]/delete[]运算符, 注意这并非重载全局的new/delete.这里仅贴出来重载new/delete的部分:
- inline void *operator new(size_t numbytes, RTPMemoryManager *mgr, int memtype)
- {
- if (mgr == 0)
- return operator new(numbytes);
- return mgr->AllocateBuffer(numbytes,memtype);
- }
-
- inline void operator delete(void *buffer, RTPMemoryManager *mgr, int memtype)
- {
- if (mgr == 0)
- operator delete(buffer);
- else
- mgr->FreeBuffer(buffer);
- }
用户如果需要自己来管理内存,只要编写自己的class,并继承自RTPMemoryManager 即可,当然最重要的是需要重载该类的纯虚函数. 如果仅仅是这些, 还谈不上设计得巧妙, 还有个重要的类是
RTPMemoryObject 这个类非常简单:
- class RTPMemoryObject
- {
- protected:
- RTPMemoryObject(RTPMemoryManager *memmgr) : mgr(memmgr) { }
- virtual ~RTPMemoryObject() { }
-
- RTPMemoryManager *GetMemoryManager() const { return mgr; }
- void SetMemoryManager(RTPMemoryManager *m) { mgr = m; }
-
- private:
- RTPMemoryManager *mgr;
- };
根据jrtplib库的实现,这个类的作用,是将具体工作的class与RTPMemoryManager class分离, 例如将RTPSession class 与 RTPMemoryManager class 分离. 这在设计模式里貌似是叫适配器模式.
整个jrtplib库中最重要的class, 也就是RTPSession, 它是继承自:RTPMemoryObject
这样在内部实现中,通过RTPMemoryObject::GetMemoryManager() 函数来将用户实现的内存管理类获得,然后通过new的重载运算符 从而调用RTPMemoryManager::AllocateBuffer , 语法如下:
OneClass *p = new(GetMemoryManager() /* 返回RTPMemoryManager指针 */, x) OneClass();
根据C++ operator new的描述, 这个调用,相当于是调用函数:
void *operator new(size_t numbytes, RTPMemoryManager *mgr, int memtype);
其中,第一个参数是OneClass的字节数,
第二个参数是上面new()中的第一个参数,
第三个参数是上面new()中的第二个参数.
而由于C++多态的特性, 在RTPMemoryManager类重载的那个new实现中, AllocateBuffer function, 最终会调用用户编写的那个重载过的函数. 这在jrtplib库中的examples/examples5.cpp 文件中有示例.
代码看到这, 其实已经理解得差不多了, 确实很久没有看到设计得这么简洁的类了.但这是在现有的代码上分析,看到的是已经设计好的class和接口,自然一目了然. 那如果没有RTPMemoryObject这个类, 代码会是什么样子呢?
我觉得要么是增加全局的RTPMemoryManager实例, 这要求程序员做更多的事情,明显不是一个好的方案.
第二种方式是, 在RTPSession中增加RTPMemoryManager指针, 在构造RTPSession类时,将该指针传入,这同目前的实现接口是一样的,这种方式我没有想到有什么不好的地方,这是"has a", 而目前的实现更像是"is a".
转载自:http://blog.chinaunix.net/uid-8489474-id-3011297.html