我的编程习惯:RAII
关于RAII(Resource Acquisition Is Initialization),以下两点是关键。
- 获得资源后立刻放进管理对象(managing object)内: 在获得一笔资源后与同一语句内以它初始化某个管理对象。
- 管理对象运用析构函数确保资源被释放: 无论控制流如何离开程序块,一旦对象被销毁(例如当对象离开作用域),其析构函数自然会被自动调用,于是资源被释放。
一,常见用法
RAII最常见的应用就是智能指针。
我们知道对于程序块中动态分配的堆对象,应该保证当控制流离开程序块时被释放。
1: void func()
2: {
3: Foo* foo = new Foo;
4: ... //这里可能抛出异常,造成delete无法调用
5: delete foo;
6: }
如果new和delete之间抛出异常,就会出现资源泄漏。运用智能指针,可以有效的避免资源泄漏。
1: void func()
2: {
3: std::auto_ptr<Foo> foo(new Foo); //在单独语句内以堆对象初始化智能指针
4: ... //这里即使抛出异常,delete也会随着智能指针的析构函数被调用
5: }
二,扩展用法
其实不仅仅是资源的获取和释放,RAII可以广泛用于保持前后状态的一致。
在用GDI+的时候我们知道要先调用初始化函数,用完了要调用关闭函数。于是我们可以创建一个类,吧初始化函数写进类构造函数,关闭函数写进析构函数。
1: class GdiplusSwitch
2: {
3: public:
4: GdiplusSwitch()
5: {
6: Gdiplus::GdiplusStartupInput startupinput;
7: Gdiplus::GdiplusStartup(&_token,&startupinput,NULL); //初始化函数
8: }
9:
10: ~GdiplusSwitch()
11: {
12: Gdiplus::GdiplusShutdown(_token); //关闭函数
13: }
14:
15: private:
16: ULONG_PTR _token;
17: };
这样我们就只需要在用GDI+之前实例化一个类的对象。
1: void func()
2: {
3: GdiplusSwitch gdi;
4: ... //继续做事,当对象离开作用域时,关闭函数会随着析构函数被调用
5: }
当然你也可以结合智能指针一起用。
1: void func()
2: {
3: std::auto_ptr<GdiplusSwitch> gdi(new GdiplusSwitch);
4: ... //当对象离开作用域时,智能指针析构函数调用delete,delete调用类析构函数,类析构函数最终调用关闭函数
5: }
再举个例子,用MFC调用标准打开文件的模式对话框,可能会引起当前工作目录的改变。这就需要先记下当前目录,在模式对话框之后将被改变的目录再改回来。先来定义一个类,
1: class WorkDirectoryHolder
2: {
3: public:
4: WorkDirectoryHolder()
5: {
6: _wgetcwd(m_workpath,_countof(m_workpath)); //记下当前工作目录
7: }
8:
9: ~WorkDirectoryHolder()
10: {
11: _wchdir(m_workpath); //改变当前工作目录
12: }
13:
14: private:
15: WorkDirectoryHolder(const WorkDirectoryHolder&){}
16: const WorkDirectoryHolder& operator= (const WorkDirectoryHolder&){}
17:
18: private:
19: wchar_t m_workpath[256];
20: };
然后如此运用:
1: void OnBnClickedOpenButton()
2: {
3: std::auto_ptr<WorkDirectoryHolder> wdh(new WorkDirectoryHolder);
4:
5: CFileDialog dlgFile(TRUE);
6: ...
7: dlgFile.DoModal();
8:
9: ... //对象离开作用域时,工作目录将自动改回
10: }
日常生活中类似的情形也很多见,好比说东西从哪里拿的,用完了再放回那里去。养成好的习惯,可以带来很多便利,同样,好的编程习惯,也可以防止一些不必要错误的产生,从而降低维护成本。
-----------------------------------------------------------------
最后放张电子名片看看,嘿嘿,大家果断加我: