// HandleTest2.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <iostream> using namespace std; #include "SmartHandle.h" #include "SmartPtr.h" #include "TestClass.h" // Testing the CAutoHandle template class. // Additional feature: misusing of handle wrapper as pointer // is not compiled. int _tmain(int argc, _TCHAR* argv[]) { // test smart handles CAutoLibrary hLibrary; hLibrary = LoadLibrary(_T("psapi.dll")); CAutoGeneralHandle hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); SetEvent(hEvent); // hLibrary->unused = 0; // not compiled, exactly as needed // test smart pointers CAutoPointer<CTestClass>::AutoPtr pTest = new CTestClass(); pTest->DoSomething(); CAutoArrayPointer<CTestClass>::AutoPtr pArrayTest = new CTestClass[2]; return 0; }
// SmartPtr.h#pragma once// Additional release algorithms which allow to use// CSmartHandle as smart pointer// *******************************************************************************// Release algorithm for plain pointer.// Using this release algorithm CSmartHandle works// like simple smart pointer.template <typename T, class PointedBy>struct CClosePointer{ void Close(T handle) { delete (PointedBy*)handle; }protected: ~CClosePointer() { }};// I want to make typedef for using CSmartHandle with CClosePointer policy.// However, I cannot do this because user needs to provide class name parameter.// I can use define:// #define CAUTOPOINTER(ClassName) CSmartHandle<ClassName*, CClosePointer, ClassName>// Client code is:// CAUTOPOINTER(CTestClass) pTestClass = new CTestClass(); but more elegant solution is constructing new type:template <class T>struct CAutoPointer{ typedef CSmartHandle<T*, CClosePointer, T> AutoPtr;};// Client code is:// CAutoPointer<CTestClass>::AutoPtr pTestClass = new CTestClass(); the struct CAutoPointer itself has no members apart from the type definition // and isn't instantiated, it's only used to provide the type member // which returns the type I need.// *******************************************************************************// Release algorithm for plain array.template <typename T, class PointedBy>struct CCloseArrayPointer{ void Close(T handle) { delete[] (PointedBy*)handle; }protected: ~CCloseArrayPointer() { }};//#define CAUTOARRAYPOINTER(ClassName) CSmartHandle<ClassName*, CCloseArrayPointer, ClassName>template <class T>struct CAutoArrayPointer{ typedef CSmartHandle<T*, CCloseArrayPointer, T> AutoPtr;};
在写代码时候,经常会将一个Handle关闭多次,或者不关闭,包括内存释放也同样.可能大部分人觉得对一个handle关闭多次不会有问题, 但在管家项目中,就出现这样的Crash.
为了防止这样的问题: 就必须使用智能指针.
// SmartHandle.h #pragma once // Class CSmartHandle works like Jeffrey Richter's EnsureCleanup class // (Windows HANDLE wrapper which releases handle in destructor). // The change: instead of release function pointer it uses template // class (using the same technique as described in // Modern C++ Design by Andrei Alexandrescu. // // Classes CCloseHandle, CCloseRegKey... are releasing policies. // These classes are templates. Class CSmartHandle has second parameter // ReleaseAlgorithm which is release policy template. // This means, CSmartHandle template declaration contains // nesting template. This code is compiled in Visual Stidio .NET 2003 // but not compiled in previous versions. // // Protected destructors prevent client code to release CSmartHandle // using release pointer code (see Modern C++ Design, // 1.7 Destructors of Policy Classes). // // Additional PointedBy algorithm prevents misusing of the smart handle // instance as smart pointer (using -> with handle is not compiled). // Release algorithms (release policies) template <typename T, class PointedBy> struct CCloseHandle { void Close(T handle) { cout << "Handle is released" << endl; // for testing CloseHandle(handle); } protected: ~CCloseHandle() { } }; template <typename T, class PointedBy> struct CCloseRegKey { void Close(T handle) { RegCloseKey(handle); } protected: ~CCloseRegKey() { } }; template <typename T, class PointedBy> struct CCloseLibrary { void Close(T handle) { cout << "Library is released" << endl; // for testing FreeLibrary(handle); } protected: ~CCloseLibrary() { } }; template <typename T, class PointedBy> struct CCloseViewOfFile { void Close(T handle) { UnmapViewOfFile(handle); } protected: ~CCloseViewOfFile() { } }; // Empty class used as default CAutoHandle template parameter. class CEmptyClass { }; // Class CSmartHandle which implements release policy. // Second template parameter is ReleaseAlgorithm which is template itself. template <typename HandleType, template <class, class> class ReleaseAlgorithm, class PointedBy = CEmptyClass, // used for smart pointers HandleType NULL_VALUE = NULL> class CSmartHandle : public ReleaseAlgorithm<HandleType, PointedBy> { public: CSmartHandle() { m_Handle = NULL_VALUE; } CSmartHandle(HandleType h) { m_Handle = h; } HandleType operator=(HandleType h) { CleanUp(); m_Handle = h; return(*this); } operator HandleType() { return m_Handle; } PointedBy* operator->() // for using as smart pointer { // NOTE: adding this operator allows to use CAutoHandle object as pointer. // However, if PointedBy is CHandlePlaceHolder (used for handles), // this is not compiled because CHandlePlaceHolder has no functions. // This is exactly what I need. return m_Handle; } BOOL IsValid() { return m_Handle != NULL_VALUE; } ~CSmartHandle() { CleanUp(); } protected: void CleanUp() { if ( m_Handle != NULL_VALUE ) { Close(m_Handle); m_Handle = NULL_VALUE; } } HandleType m_Handle; }; // Client code (definitions of standard Windows handles). typedef CSmartHandle<HANDLE, CCloseHandle> CAutoGeneralHandle; typedef CSmartHandle<HKEY, CCloseRegKey> CAutoRegKey; typedef CSmartHandle<PVOID, CCloseViewOfFile> CAutoViewOfFile; typedef CSmartHandle<HMODULE, CCloseLibrary> CAutoLibrary; typedef CSmartHandle<HANDLE, CCloseHandle, CEmptyClass, INVALID_HANDLE_VALUE> CAutoFile;
防止handle忘记关闭,或者被关闭多次,以及防止内存忘记释放,或者释放多次
最新推荐文章于 2022-11-10 18:30:40 发布