一、RAII是什么?
RAII全称为(Resource Acquisition Is Initialization),即“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。
C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。利用这个特性就可以很好的管理创建好的资源。比如锁、信号、指针这类成套操作的资源,即有创建有销毁。
个人理解:RAII机制或者RAII思想,简单的说,把需要创建的资源封装到类里面,在类的构造函数完成对资源的初始化,在类的析构函数中完成对资源的释放。
二、RAII的实现
先看一下忘记释放内存的结果是什么?
#include <iostream>
using namespace std;
int main()
{
for(int i= 0;i< 10000000; i++)
{
int* data = new int[5];
data[0] = i;
data[1] = i;
data[2] = i;
data[3] = i;
data[4] = i;
//delete []data;
}
system("pause");
return 0;
}
可以看到,这个小程序的占用内存达到了300多M;下面是添加上delete的程序内存占用情况
所以在我们使用一些资源时忘记释放对于一些项目往往是很严重的,资源友好的释放也是c++程序员必备的素养。
利用RAII思想的代码实现如下:
使用模板类,能更好增加程序的可扩展性。
#ifndef RAII_TOOL_H
#define RAII_TOOL_H
template<class T>
class raII_tool
{
public:
raII_tool(T *t):_t(t)
{
std::cout<<"raII_tool 构造函数被调用!"<<std::endl;
}
//析构函数完成资源的释放
~raII_tool()
{
std::cout<<"raII_tool 析构函数被调用!"<<std::endl;
delete []_t;
}
//获取创建好的资源指针
T * getPtr()
{
return _t;
}
private:
T *_t;
};
#endif // RAII_TOOL_H
#include <iostream>
#include "raII_tool.h"
int main()
{
std::cout<<"main 函数执行!"<<std::endl;
for(int i= 0;i< 1000000; i++)
{
auto raIITool = raII_tool<int>(new int[5]);
int *data = raIITool.getPtr();
data[0] = i;
data[1] = i;
data[2] = i;
data[3] = i;
data[4] = i;
}
std::cout<<"main 结束执行!"<<std::endl;
system("pause");
return 0;
}
结果如下:
下面仔细的分析一下情况,这是调整循环次数为5,打印出的结果。
raIITool这个对象的生命周期在大括号里面,每次调用raII_tool的构造函数,把new的内存地址传入构造函数并赋值给_t,在raIITool生命周期终止时调用析构函数,释放内存资源。RAII机制达到了自动释放资源的效果,与智能指针同理。
三、利用RAII思想封装sem信号
#ifndef SEM_H
#define SEM_H
#include <semaphore.h>
class sem
{
public:
//构造函数初始化信号量
sem()
{
if (sem_init(&m_sem, 0, 0) != 0)
{
throw std::exception();
}
}
sem(int num)
{
std::cout<<"初始化信号"<<std::endl;
if (sem_init(&m_sem, 0, num) != 0)
{
throw std::exception();
}
}
//析构函数释放信号量
~sem()
{
std::cout<<"释放信号"<<std::endl;
sem_destroy(&m_sem);
}
//sem_wait函数将以原子操作方式将信号量减一,信号量为0时,sem_wait阻塞
bool wait()
{
return sem_wait(&m_sem) == 0;
}
//sem_post函数以原子操作方式将信号量加一,信号量大于0时,唤醒调用sem_post的线程
bool post()
{
return sem_post(&m_sem) == 0;
}
private:
sem_t m_sem;
};
#endif // SEM_H
析构的时候就可以自动释放信号啦!
四、总结
RAII机制使用远不止于此,上文只是简单的举一个小例子来说明RAII机制整体的一个思想,在真正的编程中,如果能够准确判断出内存释放的时机,可以直接选择delete掉内存。根据不同的环境选择不同的方法。