抛开析构函数

内存管理通常指的是堆上分配的空间,栈上分配虽然高效好用,但一般是固定大小的、不能持久保存的。堆上分配就有了释放的问题,代码中有一些是使用new/malloc来分配空间的,还有一些是使用内存池,如何在释放时区分是必须的。

简单思考以后我感觉首先需要排除delete pObject这种调用,这显然是假定对象是用new分配出来的,或者是对象重载了new/delete操作符。也可以把对象根据分配方式不同放在不同的容器中管理,不过带来了查找上的开销。如果不分类放在容器中,也可以让对象自己知道是如何分配的,再给它一个销毁的函数:


struct Foo {
int allocMethod;

void Destroy() {
switch(allocMethod) {
case ALLOC_NEW: delete this; break;
case ALLOC_MALLOC: // placement delete + free break;
// ... memory pool or object pool
}
};


这么写会很累,每个对象都要知道太多细节,可以考虑把这部分提出来:


struce DestroyCallback {
virtual call(void* p) = 0;
};

struct Foo {
DestroyCallback* destorycb;

void Destory() {
if (destroycb)
destroycb->call(this);
}
};

struct DeleteCallback : public DestroyCallback {
virtual void call(void* p) {
delete static_cast<Foo*>(p);
}
};

struct PoolFreeCallback : public DestroyCallback {
Pool<Foo>* pool;

virtual void call(void* p) {
pool->Release(static_cast<Foo*>(p));
}
};


这种方式在分配对象的时候把destroy callback设置好,需要释放时调用Destroy就可以了,如果对象需要在一个流程中传递并且在最后阶段销毁,这种方式很容易解除前后端分配器的耦合。使用这种方式就需要用Destroy来代替其它销毁对象的方式,因为它并不一定真的表示销毁,对于对象池来说,它完成的是对象的归还。考虑到池对象重用时前需要初始化,我给对象加上一个初始化方法。由于Destroy并不能准确表明对象的生成状态,我改用Open/Close来代替,Open表明一个对象的重生,通常用来初始化一些变量的值,并不是取代构造函数,这特别适合一些需要池化的大对象,Close也不是析构,但它也可以真正完成析构调用。对于一些特殊的应用,还可以在Open里面完成构造函数调用,Close里面完成析构函数调用,如果对象的空间是使用malloc/free来管理的,这种方式就显得特别有用。这种方式还有一个额外的好处,很多C++开发者不喜欢使用异常,但构造函数没有返回值,只能使用异常来表示失败,多一个Open方法可以有一个不使用异常来检查错误的方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值