设计实现C++内存的半自动释放(一)

2014-11-24 09:25:38 · 作者: · 浏览: 1
C++的一大优点就直接提供了内存的申请和使用功能,让程序员可以根据自己的需要,通过alloc系列函数或new运算符来申请使用内存,但是C++却不像java或C#那样,提供了垃圾的自动回收机制,我们申请的内存要由自己来管理、自己来释放,也就是说,C++把内存管理的责任完全交给了程序员。申请资源是简单的,在需要的时候申请就可以了,然而请神容易送神难,内存的释放却是一个非常让人头痛的问题。有的程序员忘记了释放申请的内存(堆中的内存),有的程序员对一块释放了的内存,再次释放等等,都引发了一系列的错误。
内存管理是C++最令人痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的性能,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在。难道使用C++就不能像使用C#或java那样,不管内存的释放吗?其实我们可以通过适当的设计来减轻我们对内存的管理任务。虽然不能像C#或java那样,完全不管内存的使用和释放,但是也能在很大程度上减轻我们对内存的管理压力。下面就以本人设计的一个基类说明一下,如何实现C++内存的半自动释放。至于为什么说是半自动释放,看完这篇文章你就会知道了,现在可以不必深究。
一、设计思想 我们知道,在C++中,当一个对象被释放时,它的析构函数必定会被调用,而如果该对象的类型是一个子类,则其先调用自己的析构函数,再调用其父类的析构函数。所以我们可以利用这个特性设计一个基类Object,它的责任就是负责释放它的子类申请的资源。而释放的操作,我们可以放在析构函数中。
在基类Object中保存一个链表childern,链表childern中的值是其new出来的对象的指针,我把该对象叫做父对象,由该对象new出来的对象叫做子对象,例如: A a; a.createObj(); 类A是基类Object的子类,对象a通过调用其成员函数createObj来创建了10个B类(也是Object的派生类)的对象,则a就是父对象,而那10个B类的对象就是子对象。当父对象析构时,就会调用Object的析构函数,从而会把它的所有子对象释放掉。也就是说,当a被释放时,就会调用Object类的析构函数,从而释放它new出来的10个子对象(B类的对象)。这样,就可以简化我们对内存的管理。
PS:这个实现机制是参考Qt的内存管理机制。
二、实现代码 ps: 完整的实现代码可以点击这里
Object的头文件(object.h)如下:
#ifndef OBJECT_H
#define OBJECT_H
#include 
  
   
using std::list;
class Object;
typedef list
   
     ObjectList; class Object { public: virtual ~Object(); //重新设置对象的父对象 void setParent(Object *parent); //获得当前对象的子对象列表 inline const ObjectList& getChildern() const; //获得当前对象的父对象 inline const Object* getParent() const; protected: explicit Object(Object *parent = NULL); Object(const Object& obj); Object& operator= (const Object &obj); private: //把当前对象插入到parent指向的父对象的子对象列表中 inline void _appendObjectList(Object *parent); ObjectList childern;//子对象列表 Object *this_parent;//指向对象的父对象 }; void Object::_appendObjectList(Object *parent) { /*** 函数功能:把当前对象插入到parent指向的父对象的子对象列表中 返回:无 ***/ this_parent = parent;//设置当前对象的父对象 //若其父对象不为空,则加入到父对象的子对象列表中 if(this_parent != NULL) this_parent->childern.push_back(this); } const ObjectList& Object::getChildern() const { return childern; } const Object* Object::getParent() const { return this_parent; } #endif // OBJECT_H
   
  


Object的实现文件(object.cpp)如下:
#include object.h
#include 
  
   
Object::Object(Object *parent)
    :this_parent(parent)
{
    /***
    函数功能:创建一个Object对象,若其parent不为空,
        则把当前对象插入到其子对象列表中
    ***/
    if(this_parent != NULL)
        this_parent->childern.push_back(this);
}
Object::Object(const Object& obj)
{
    /***
    函数功能:根据对象obj,复制一个对象
    ***/
    //复制时,只是把当前对象和obj的父对象设置为同一个父对象
    //并不复制obj的子对象列表
    _appendObjectList(obj.this_parent);
}
Object& Object::operator= (const Object &obj)
{
    /***
    函数功能:若当前对象无父对象,则把obj的父对象设置成当前对象的父对象
    返回:当前对象的引用
    ***/
    if(this_parent == NULL)
    {
        _appendObjectList(obj.this_parent);
    }
    return *this;
}
Object::~Object()
{
    /***
    函数功能:释放由该对象new出来的子对象
    ***/
    //若当前对象有父对象,则将当前对象从共父对象的子对象列表中删除
    if(this_parent != NULL)
    {
        ObjectList::iterator it =
            find(this_parent->childern.begin(),
                 this_parent->childern.end(),
                 this);
        this_parent->childern.erase(it);
// this_parent->childern.remove(this);
    }
    //释放其new出来的子对象
    while(!childern.empty())
    {
        ObjectList::iterator it(childern.begin());
        delete *it;
    }
}
void Object::setParent(Object *parent)
{
    /***
    函数功能:重新设置对象的父对象
    返回:无
    ***/
    //若当前对象有父对象,则把当前对象从其父对象的子对象列表中删除
    if(this_parent != NULL)
    {
        ObjectList::iterator it =
            find(this_parent->c