防止handle忘記關閉,或者被關閉多次,以及防止內存忘記釋放,或者釋放多次

// 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;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章