CSDN的博客管理真烂。草稿箱里的文章又莫名其妙的没了。好吧,又得重写,细节实在没兴趣写第二遍了,真TM扫兴!
这几章是内存越界检查的。内存越界检查也有很多工具。并且程序员自己也可以在内存块后面加一个额外的保护页,再将页的属性设置为不可读写(VirtualAlloc、VirtualProtect),这样一旦访问到保护页,系统会抛出异常。但是对于大型的复杂软件,并且bug涉及到多线程,有一定随机性的话,这种方式以及其他很多工具可能都会无能为力。
从本质上说,如果程序员在每个用到指针的地方都做指针的范围判断,那么指针越界就不是个问题了。然而你无法保证程序员会这么做(可能没有任何一个程序员会这么做),因为这样无论是编程效率还是运行效率都太慢了。运行效率还好办,你可以在不需要做越界检查时(比如正式的发布版本)将这些判断语句去掉,这并不是一件困难的事情,用个宏开关就行了。然而在每个用到指针的地方都加范围判断实在是太繁琐了。
这里就可以用到C++的封装了。我们可以把指针封装在一个对象里,并且让这个对象表现的像个指针。如果你用过智能指针,那么对这个应该会比较熟悉。接下来,我们只要对所有的指针内容的访问通道进行封装,加入范围判断就可以了。这些访问通道包括*
、[]
、->
。当然,还有一些指针的操作,比如++
、+
、-
、==
、!=
等等等等。
不多说了,自己看程序吧。这些程序放在与内存池不同的一个头文件里。
//
// Reference structure
//
struct SmartHeapMemData
{
DWORD_PTR m_pStartMemPtr; // pointer to the starting address of the memeory block really being used in the app
DWORD_PTR m_pEndMemPtr; // pointer to the ending address of the memeory block really being used in the app
int m_nRefCnt; // reference count, to allow fast copy
};
//
// Smart heap memory pointer class
//
template<typename T> class __declspec(dllexport) SmartHeapMemPtr
{
public:
SmartHeapMemData* m_pData;
T* m_pPtr; // pointer currently being used in the app
int m_nUnmanagedLen; // length of the memory block externally allocated (e.g. by modules from third party)
public:
// Constructor
SmartHeapMemPtr() : m_pData(0), m_pPtr(0), m_nUnmanagedLen(0) {};
template<typename t2> SmartHeapMemPtr(const SmartHeapMemPtr<t2>& p) { if ((m_pData = p.m_pData) != 0) IncRef(); m_pPtr = (T*) p.m_pPtr; };
SmartHeapMemPtr(const SmartHeapMemPtr& p) { if ((m_pData = p.m_pData) != 0) IncRef(); m_pPtr = p.m_pPtr; };
SmartHeapMemPtr(const T* p) : m_pData(0), m_nUnmanagedLen(0) { *this = p; };
// Destructor
~SmartHeapMemPtr() { Release(); };
// Assignment operator
SmartHeapMemPtr& operator=(const T* p)
{
if (m_pData)
DecRef();
m_pData = new SmartHeapMemData;
m_pData->m_nRefCnt = 1;
if (p)
{
m_pData->m_pStartMemPtr = (DWORD_PTR) p;
PPREFIX pPrefix = IsManagedMemory((void*) p);
if (pPrefix)
{
m_pData->m_pEndMemPtr = m_pData->m_pStartMemPtr + pPrefix->d.pPostfix->nActualSize - 1;
if (pPrefix->d.nRefCnt == 0) // not already assigned to a smart pointer, so the calling is something like "watever* p = new whatever(...)"
m_pData->m_nRefCnt ++; // otherwise, the intelligenet garbage collection will do garbage collection even if there is no corresponding delete command
pPrefix->d.nRefCnt ++;
}
else
m_pData->m_pEndMemPtr = (DWORD_PTR) p + m_nUnmanagedLen - 1;
}
else
m_pData->m_pStartMemPtr = m_pData->m_pEndMemPtr = 0;
m_pPtr = (T*) p;
return *this;
};
SmartHeapMemPtr& operator=(const SmartHeapMemPtr<T>& p)
{
if (m_pData)
{
if (m_pData == p.m_pData) // already the same
goto SMART_HEAP_ASSIGN_END;
DecRef();
}
if ((m_pData = p.m_pData) != 0)
IncRef();
SMART_HEAP_ASSIGN_END:
m_pPtr = p.m_pPtr;
return *this;
};
// Set the unamanged length
BOOL SetUnmanagedLength(const int nLen)
{
if (IsManagedMemory((void*) m_pData->m_pStartMemPtr))
return FALSE;
m_nUnmanagedLen = nLen;
m_pData->m_pEndMemPtr = m_pData->m_pStartMemPtr + nLen;
return TRUE;
};
// Pointer like syntax and semantics
inline T* operator->()
{
if ((DWORD_PTR) m_pPtr < m_pData->m_pStartMemPtr || (DWORD_PTR) m_pPtr > m_pData->m_pEndMemPtr + 1 - sizeof(T)) // 越界检查
throw char("Pointer bounds error!");
return m_pPtr;
};
inline T& operator*()
{
if ((DWORD_PTR) m_pPtr < m_pData->m_pStartMemPtr || (DWORD_PTR) m_pPtr > m_pData->m_pEndMemPtr + 1 - sizeof(T)) // 越界检查
throw char("Pointer bounds error!");
return *m_pPtr;
};
inline const T* operator->() const { return m_pPtr; };
inline const T& operator*() const { return *m_pPtr; };
// Comparision operators
bool operator==(const T* p) const { return (p == m_pPtr); };
bool operator!=(const T* p) const { return (p != m_pPtr); };
bool operator==(const SmartHeapMemPtr& p) const { return (p.m_pPtr == m_pPtr); };
bool operator!=(const SmartHeapMemPtr& p) const { return (p.m_pPtr != m_pPtr); };
bool operator>(const SmartHeapMemPtr& p) const { return (m_pPtr > p.m_pPtr); };
bool operator<(const SmartHeapMemPtr& p) const { return (m_pPtr < p.m_pPtr); };
// Arithmetic operators
SmartHeapMemPtr<T> operator+(const int n) { SmartHeapMemPtr<T> ret; ret.m_pData = m_pData; ret.IncRef(); ret.m_pPtr = m_pPtr + n; return ret; };
const SmartHeapMemPtr<T> operator+(const int n) const { SmartHeapMemPtr<T> ret; ret.m_pData = m_pData; ret.IncRef(); ret.m_pPtr = m_pPtr + n; return ret; };
SmartHeapMemPtr<T> operator-(const int n) { SmartHeapMemPtr<T> ret; ret.m_pData = m_pData; ret.IncRef(); ret.m_pPtr = m_pPtr - n; return ret; };
const SmartHeapMemPtr<T> operator-(const int n) const { SmartHeapMemPtr<T> ret; ret.m_pData = m_pData; ret.IncRef(); ret.m_pPtr = m_pPtr - n; return ret; };
template<typename t2> int operator-(SmartHeapMemPtr<t2> p) { return (int) ((DWORD_PTR) m_pPtr - (DWORD_PTR) p.m_pPtr); };
template<typename t2> int operator-(const SmartHeapMemPtr<t2> p) const { return (DWORD_PTR) m_pPtr - (DWORD_PTR) p.m_pPtr; };
// Compound assignment operators
SmartHeapMemPtr<T> & operator+=(const int n) { m_pPtr += n; return *this; };
SmartHeapMemPtr<T> & operator-=(const int n) { m_pPtr -= n; return *this; };
SmartHeapMemPtr<T> & operator++() { m_pPtr ++; return *this; };
SmartHeapMemPtr<T> & operator--() { m_pPtr --; return *this; };
SmartHeapMemPtr<T> & operator++(int) { m_pPtr ++; return *this; };
SmartHeapMemPtr<T> & operator--(int) { m_pPtr --; return *this; };
// Member operators
inline T& operator [](const int n)
{
if ((DWORD_PTR) (m_pPtr + n) < m_pData->m_pStartMemPtr || (DWORD_PTR) (m_pPtr + n) > m_pData->m_pEndMemPtr + 1 - sizeof(T)) // 越界检查
throw char("Pointer bounds error!");
return m_pPtr[n];
};
inline const T& operator [](const int n) const
{
if ((DWORD_PTR) (m_pPtr + n) < m_pData->m_pStartMemPtr || (DWORD_PTR) (m_pPtr + n) > m_pData->m_pEndMemPtr + 1 - sizeof(T)) // 越界检查
throw char("Pointer bounds error!");
return m_pPtr[n];
};
// Cast operator
template<typename t2> operator t2() { return (t2) m_pPtr; };
template<typename t2> operator t2() const { return (t2) m_pPtr; };
// Release
void Release() { if (m_pData) DecRef(); m_pData = 0; m_pPtr = 0; };
// Decrease reference
void DecRef()
{
m_pData->m_nRefCnt --;
if (m_pData->m_nRefCnt == 0)
{
if (m_pData->m_pStartMemPtr)
{
PPREFIX pPrefix = IsManagedMemory((void*) m_pData->m_pStartMemPtr);
if (pPrefix) // fully managed
{
pPrefix->d.nRefCnt --;
if (pPrefix->d.nRefCnt == 0)
{
if (pPrefix->d.bIsArray)
DEL_ARRAY((T*) m_pData->m_pStartMemPtr)
else
DEL_PTR((T*) m_pData->m_pStartMemPtr)
}
}
// else
// throw char("Deleting unmanaged memeory!");
}
delete m_pData;
m_pData = NULL;
}
};
private:
// Add reference
void IncRef()
{
m_pData->m_nRefCnt ++;
};
// Check if it is fully managed, partially managed or unmanaged. Return a prefix if fully managed
PPREFIX IsManagedMemory(void *p)
{
const static int PREFIX_SIG = ('p' << 24) | ('r' << 16) | ('f' << 8) | 'x';
__try
{
// For array elements that have destructors, C++ will allocate 4 bytes more than requested and fill the first 4 bytes with
// length of array. So, we here need to check if it is such case.
if (((DWORD_PTR) p) % ALIGNMENT != 0) // not aligned as expected (this points to offset 4 in the allocated memory)
p = (void*) (((DWORD_PTR) p) & ~(ALIGNMENT - 1));
PPREFIX pPrefix = (PPREFIX) p - 1;
if (*((int*) pPrefix->d.szToken) == PREFIX_SIG)
return pPrefix;
else
return NULL;
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return NULL;
}
};
};
}