智能指针是为了解决程序员创建了资源而忘记释放造成内存泄漏的问题,可减少代码编写过程中的代码长度,减少程序员对资源管理的难度,因而在COM组件及各类插件中有广泛应用。
1、智能指针的原理
智能指针的原理是利用对象在离开作用域时会调用对象的析构函数,将资源指针封装进类中,并将资源指针的释放过程写入析构函数中,这样就能在对象释放时自动释放资源。
一个管理注册表句柄的智能指针示例如下:
class CSPHKey : public CBase_Uncopy { private: HKEY m_hKey; public: CSPHKey(HKEY hKey) { m_hKey = hKey; } virtual ~CSPHKey() { RegCloseKey(m_hKey); } }
2、智能指针的注意事项
智能指针由于是用类对象实现的,所以如果有对象复制过程(如函数传值调用),会产生多个智能指针对象,对象释放的过程会多次在析构函数中释放资源,会造成不可预知的意外,故要防止这种情况发生,一般可采取禁止对象复制的方式或者采用引用计数的方式来解决这个问题,下面给出一个Effective C++中的例子,只要继承这个类即可防止对象被复制:
class CBase_Uncopy { protected: CBase_Uncopy() {} //允许继承对象的构造和析构 ~CBase_Uncopy() {} private: CBase_Uncopy(const CBase_Uncopy&); //不允许拷贝构造 CBase_Uncopy& operator = (const CBase_Uncopy&); //不允许用另一个对象拷贝构造 };
3、完整的管理注册表句柄的智能指针示例
class CSPHKey : public CBase_Uncopy { private: HKEY m_hKey; public: CSPHKey(HKEY hKey) { m_hKey = hKey; } //无参构造函数 CSPHKey() { m_hKey = NULL; } virtual ~CSPHKey() { Close(); } //取hKey HKEY GetHKey() { return m_hKey; } //关闭hKey LSTATUS Close() { LSTATUS ls = ERROR_SUCCESS; if (m_hKey) { ls = RegCloseKey(m_hKey); m_hKey = NULL; } return ls; } //重载*操作符,允许直接取hKey值 operator HKEY() const { return m_hKey; } //重载赋值操作符,允许直接用HKEY赋值 void operator = (HKEY& hKey) { m_hKey = hKey; } //重载 & 操作符,允许取HKEY的指针 HKEY* operator & () { return &m_hKey; } };
由于重载了复制操作符和取值操作符,我们可以像使用HKEY一样对智能指针进行赋值,取址等操作。
CSPHKey shPluginKey; //对智能指针取址 RegOpenKeyEx(HKEY_LOCAL_MACHINE, _("SoftWareMozillaPlugins est"), NULL, KEY_WRITE, &shPluginKey)); //使用智能指针替代HKEY句柄 ULONG ulData = 2; RegSetValueEx(shPluginKey, _T("test"), NULL, REG_DOWRD, &ulData, sizeof(ulData));
我们还可以修改这个类,把Close改为其他资源释放的函数(如CloseHandle()),使其变成其他资源类型的智能指针。