防止handle忘记关闭,或者被关闭多次,以及防止内存忘记释放,或者释放多次

来源:互联网 发布:中国cpu 知乎 编辑:程序博客网 时间:2024/04/29 03:59
// 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;

原创粉丝点击