借刀杀对象--Raii技法(C++版)

我们都知道C++有一点很不爽的地方就是内存管理需要手动,像我有时候使用多了像C#,java之类托管语言(C#在clr中可以通过gc进行垃圾回收,java在jvm中也有相应的gc回收),再写C++就会有点不爽了,甚至会疑神疑鬼的,写完一段代码就会想想 天哪,我的代码有没有哪里忘了释放内存啊,有没有内存泄露啊,唉,写代码的乐趣就这样被一点点的抹去,这时候我们会想到C++能不能也来个内存的自动管理啊,C++本身固然也提供了std::auto_ptr 这个智能指针,通过引用计数来判断对象是不是应该被析构,当没有引用时,对象就say goodbye了,当然这个比起jvm中的堆内存管理显然有那么一点抬不起头,我在这里就不说智能指针了,智能指针会在下一篇文章中我自己来实现一个简单版本,这里我说另外一种自动完成内存管理的方法,那就是raii技法,raii是什么呢,英文展开叫做resource acquisition is initialization ,我个人真心觉得这不是个好的解释,我对于这个的理解就是通过对象的初始化来进行资源的分配,资源在这里可以指代文件啊,线程啊,或者在堆中new出来的内存等等。

那么问题来了,怎么通过本地的对象来进行资源的自动管理,在本文就主要讲述内存的管理,其实这个自动的意思就是有人帮了我们管理内存,这个值得感恩的家伙是谁呢,没错,就是cpu啦,我们知道在内存管理中栈内存中分配的内存都是由cpu进行分配以及负责对象的回收,比如在一个函数体中定义了一个局部变量,当程序超过这个函数的scope后,局部变量这个对象的生命就算到头了,他会被cpu的内置指令集自动的析构销毁,所以上面就是我下面使用raii封装指针的主要思想,首次我写一个测试的类,作为我们要进行试验的对象:

class Traii {
public:
    Traii(){}
    Traii(int){}
    int getRaii() { return val; }
    void setRaii(int rhs) { val = rhs; }

    //析构
    ~Traii()
    {
        std::cout << "destroyed" << std::endl;
    }
private:
    int val;
};

在这个类中,我在析构函数中做了手脚,在这个对象再被析构时,我就会从输出控制台看到结果,然后这个对象我不准备让操作者直接通过new运算符创建,不然怎么完成我的自动管理,所以我需要一个封装类,这个类要作为栈内存中被创建的对象,下面来看看我这个封装类:

template<class T>
class raiiTMaker
{
public:
    raiiTMaker();
    ~raiiTMaker();

    T* create(T* obj);

private:
    std::vector<T*> ptrList;
};

类的声明很简单,主要是create函数帮我们进行内存的管理,因为她会把我们创建的所有T对象放到一个l容器中,为了节约栈空间,我在容器中放的全是指针,每创建一个对象,容器就增加一个元素,当整个封装类被回收掉是,整个容器的对象就都在我们的控制范围内了,我们可以在封装类的析构函数中多做一点事情,下面看这个类的实现:

template<class T>
raiiTMaker<T>::raiiTMaker()
{
}

template<class T>
raiiTMaker<T>::~raiiTMaker()
{
    //完全析构
    while (!ptrList.empty())
    {
        T* p = ptrList.back();
        ptrList.pop_back();
        delete p;
    }
}

template<class T>
T* raiiTMaker<T>::create(T* obj)
{
    if (obj == NULL)
    {
        std::cerr << "error: Ivalid Param" << std::endl;
        return NULL;
    }
    raiiTMaker::ptrList.push_back(obj);
    return obj;
}

代码很简单,相信都可以看懂,我就不多做解释了,所以我要的效果就是当raiiTMaker 被回收时,它所管理的我们分配的内存就全被析构掉了,而且我们没有手动delete来析构我们分配的对象,现在只需要在一个函数体中分配一块栈内存给这个对象就完事了,接下来我来测试一下是不是真的自动析构掉我们的对象:

void DoWork()
{
    raiiTMaker<Traii> maker;
    for (int i = 0; i < 5; i++)
    {
        Traii* t = maker.create(new Traii());
    }
    //无析构
    //自动内存管理
}

测试也是很简单的,就是不断的创建对象就好,这里我在函数中连续分配5块内存,然后再main函数中执行这个函数,我们来看看结果:

这里写图片描述

我们可以看到,在上图中,我在函数中没有调用任何的析构函数就可以把我们分配的内存全部释放掉,这种技法在大量而且高频的分配某对象时是很有用的,因为我们不必过多忧虑是不是有那个对象忘记析构了,一切内存释放都是自动,当然这种做法比起智能指针还是没有太智能,我这里觉得这是一种快捷的技法,在接下来的文章中我会介绍更复杂的内存优化技法,比如对象池等等,敬请期待,好咯,本次文章到此结束。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值