如何养成良好的C++编程习惯(一)―― 内存管理 (二)

2014-11-24 12:08:21 · 作者: · 浏览: 1
p));
}

LPVOID ViewMap (
DWORD dwNumberOfBytesToMap,
DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh = 0,
DWORD dwDesiredAccess = FILE_MAP_ALL_ACCESS
)
{
return ::MapViewOfFile (
m_hMap,
dwDesiredAccess,
dwFileOffsetHigh,
dwFileOffsetLow,
dwNumberOfBytesToMap
);
}

BOOL UnViewMap(LPCVOID lpBaseAddress)
{
return ::UnmapViewOfFile(lpBaseAddress);
}

operator HANDLE () {return m_hMap;}
BOOL IsValid () {return m_hMap != NULL;}

private:
HANDLE m_hMap;

DECLARE_PRIVATE_COPY_CONSTRUCTOR(CFileMapping)
};

class CShareMemory
{
public:
CShareMemory(DWORD dwSize, LPCTSTR lpszName = NULL)
: m_fm(lpszName, dwSize)
{
ASSERT(dwSize > 0);
}

~CShareMemory()
{
for(set::const_iterator it = m_set.begin(); it != m_set.end(); ++it)
{
LPVOID pV = (LPVOID)*it;
ASSERT(pV);

m_fm.UnViewMap(pV);
}

m_set.clear();
}

LPVOID Alloc(DWORD dwNumberOfBytesToMap, DWORD dwFileOffsetLow)
{
LPVOID pV = m_fm.ViewMap(dwNumberOfBytesToMap, dwFileOffsetLow);

if(pV) m_set.insert((ULONG_PTR)pV);

ASSERT(pV);
return pV;
}

BOOL Free(LPCVOID lpBaseAddress)
{
ASSERT(lpBaseAddress);

set::iterator it = m_set.find((ULONG_PTR)lpBaseAddress);

if(it != m_set.end())
m_set.erase(it);

return m_fm.UnViewMap(lpBaseAddress);
}

private:

CFileMapping m_fm;
set m_set;

DECLARE_PRIVATE_COPY_CONSTRUCTOR(CShareMemory)
};

  细心的朋友一定会发觉其实这样封装是有缺点的:首先,CShareMemory 只能做内存共享,不能映射到真实文件(hFile 永远为 INVALID_HANDLE_VALUE);第二,可以对 CShareMemory 的 Alloc() 和 Free() 方法进一步封装,利用封装类的析构函数自动调用 Free(),这样就可以完全消除 “set m_set” 这个属性了;第三,CFileMapping 也可以把文件句柄一起封装进来,这样,从 CreateFile() 到 CreateFileMapping() 都受控了。这个不完美的封装就权当反面教材吧 ^_^

________________________________________

malloc() 系列函数
  很多人都建议,在 C++ 中尽量用 new 操作符取代 malloc(),因为 new 类型安全,自动调用构造函数和析构函数等等。关于这点本座略有异议,在某些情形下 malloc() 其实比 new 更好使,效率方面我们可以不计较(几乎所有编译器的 new 操作符都用 malloc() 分配内存),从事过偏底层开发的人都清楚,我们避免不了处理 row data(如:socket 的收发缓冲区等)数据,这类数据是非常适合使用 malloc() 的,用 new 分配的内存还要停顿下来想想到底是用 delete、delete[]、::delete、::delete[] 中的哪个释放,malloc() 分配的内存想都不用想,free() 包打天下,何况人家有 realloc() 可以方便地重新调整内存,你有没有 “renew” 呢?总之一句话,malloc() 的确是有存在的必要,就看接下来我们如何封装它了,请看代码:

// T : 数据类型(内置类型或结构体)
// MAX_CACHE_SIZE : 预申请内存的最大数目,以 sizeof(T) 为单位,如果该值设置合理,对于
// 需要动态递增缓冲区的 buffer 来说能大大提高效率
template
class CBufferPtrT
{
public:
explicit CBufferPtrT(size_t size = 0, bool zero = false) {Reset(); Malloc(size, zero);}
explicit CBufferPtrT(const T* pch, size_t size) {Reset(); Copy(pch, size);}
// 拷贝构造函数要分两种情形
CBufferPtrT(const CBufferPtrT& other) {Reset(); Copy(other);}
template CBufferPtrT(const CBufferPtrT& other) {Reset(); Copy(other);}

~CBufferPtrT() {Free();}

T* Malloc(size_t size = 1, bool zero = false)
{
Free();
r