目录
1.引言
2.静态缓冲区
3.动态缓冲区
4.数据引用类
5.自动数据引用类
6.几种缓冲区的类关系图
7.注意事项
8.完整代码
1.引言
在C++中,设计静态和动态缓冲区类时,需要考虑的主要差异在于内存管理的方式。静态缓冲区类通常使用固定大小的内存区域(即栈分配或静态分配),而动态缓冲区类则根据需要动态地分配和释放内存(即堆分配)。下面将分别展示这几种缓冲区类的基本设计思路。
不管是静态缓冲区还是动态缓冲区,都有统一的访问接口,于是提取共用方法,组成基础类:
template <class T>
class CSimpleDataBufferBase : public CNoncopyable
{
public:
typedef T DataType;
typedef T* DataTypePointer;
typedef T& DataTypeReference;
typedef const T ConstDataType;
typedef const T* ConstDataTypePointer;
typedef const T& ConstDataTypeReference;
public:
CSimpleDataBufferBase() {}
virtual ~CSimpleDataBufferBase() {}
public:
virtual DWORD GetSize() const = 0;
virtual DataTypePointer GetData() = 0;
virtual ConstDataTypePointer GetData() const = 0;
virtual DWORD GetMaxSize() const = 0;
operator DataTypePointer() { return GetData(); }
DataTypeReference operator*() { return *GetData(); }
DataTypeReference operator[](int nIndex);
virtual BOOL SetData(ConstDataTypePointer pData, DWORD dwSize) = 0;
virtual void Clear() = 0;
};
接口设计要点:
1)CSimpleDataBufferBase继承CNoncopyable,禁止构造拷贝和赋值拷贝。
2)访问缓冲区数据的接口,const和非const版本。
3)重载操作符*或[]访问缓冲区元素的数据
template <class T>
typename CSimpleDataBufferBase<T>::DataTypeReference CSimpleDataBufferBase<T>::operator[](int nIndex)
{
if ( (nIndex >= 0) && (nIndex < (int)GetSize()))
{
DataTypePointer pData = GetData();
return pData[nIndex];
}
else
{
throw std::out_of_range("invalid data<nIndex> position");
}
}
4)往缓冲区写数据接口,接收的是const T*和数据的长度。
5)获取缓冲区的上限。
5)清空缓冲区。
2.静态缓冲区
静态缓冲区类通常包含一个固定大小的数组(或其他容器,但数组是最直接的例子),并提供一系列方法来操作这个数组。 静态缓冲区类CStaticSimpleDataBufferT实现代码如下:
//数据静态分配
template <class T>
class CStaticSimpleDataBufferT : public CSimpleDataBufferBase<T>
{
public:
CStaticSimpleDataBufferT(DWORD dwMaxSize = MAX_STATIC_SIMPLE_BUFFER_SIZE);
virtual ~CStaticSimpleDataBufferT() { }
public:
DWORD GetSize() const { return m_dwDataLen; }
DataTypePointer GetData() { return m_sData ;}
ConstDataTypePointer GetData() const { return m_sData ;}
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize);
DWORD GetMaxSize() const { return m_dwMaxDataSize; }
void Clear() { m_dwDataLen = 0; }
private:
DataType m_sData[MAX_STATIC_SIMPLE_BUFFER_SIZE];
DWORD m_dwDataLen;
const DWORD m_dwMaxDataSize;
};
从实现的代码看,静态缓冲区就是在内存中事先分配好一段空间,这种分配一般是在栈中进行,分配速度特别快,但是不灵活,不能按照用户的大小需求分配空间。
3.动态缓冲区
动态缓冲区类通常基于动态内存分配(如new
和delete)来满足用户的需求。
静态缓冲区的大小在编译时确定,而动态缓冲区的大小则根据需要动态变化。静态缓冲区适用于那些大小已知且不会改变的场景,而动态缓冲区则更灵活,适用于大小可能变化的场景。动态缓冲区类CDynamicSimpleDataBufferT实现代码如下:
//CSimpleDataBufferBase的默认适配器
template <class T>
class CSimpleDataBufferAdapter : public CSimpleDataBufferBase<T>
{
public:
CSimpleDataBufferAdapter() : m_pData(NULL),m_dwDataLen(0) { }
virtual ~CSimpleDataBufferAdapter() { }
public:
DWORD GetSize() const { return m_dwDataLen; }
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize) { assert(0); return FALSE; }
void SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
DWORD GetMaxSize() const { assert(0); return 0; }
void Clear() { assert(0); }
DataTypePointer GetData() { return m_pData ;}
ConstDataTypePointer GetData() const { return m_pData ;}
protected:
DataTypePointer m_pData;
DWORD m_dwDataLen;
};
/动态缓冲区
template <class T>
class CDynamicSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
CDynamicSimpleDataBufferT(DWORD dwMaxSize = MAX_DYNAMIC_SIMPLE_BUFFER_SIZE);
virtual ~CDynamicSimpleDataBufferT() { ClearData(); }
public:
void Clear() { m_dwDataLen = 0; }
DWORD GetMaxSize() const { return m_dwMaxDataSize; }
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize);
protected:
void ClearData();
private:
const DWORD m_dwMaxDataSize;
};
构造函数、析构函数、赋值函数实现如下:
//构造函数
template <class T>
CDynamicSimpleDataBufferT<T>::CDynamicSimpleDataBufferT(DWORD dwMaxSize)
: m_dwMaxDataSize(dwMaxSize)
{
m_pData = new T[dwMaxSize];
if (m_pData == NULL)
throw std:: bad_alloc("new T Array Failed");
m_dwDataLen = 0;
assert(m_pData != NULL);
assert(m_dwDataLen >= 0);
}
//清空数据函数
template <class T>
void CDynamicSimpleDataBufferT<T>::ClearData()
{
if (m_pData)
delete []m_pData;
m_pData = NULL;
m_dwDataLen = 0;
}
//赋值函数
template <class T>
BOOL CDynamicSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
int i;
if (dwSize > m_dwMaxDataSize)
return FALSE;
for (i = 0; i < (int)dwSize; i++)
m_pData[i] = pData[i];
m_dwDataLen = dwSize;
return TRUE;
}
析构函数自动调用了Clear函数,释放了内存,这样就不怕退出的时候出现内存泄漏。
4.数据引用类
在前面讲解的静态缓冲区和动态缓冲区内部都需要开辟空间,而数据引用类不需要开辟空间;CRefSimpleDataBufferT的具体实现如下:
template <class T>
class CRefSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
CRefSimpleDataBufferT() { }
CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
virtual ~CRefSimpleDataBufferT() { }
public:
BOOL SetData(ConstDataTypePointer pBuffer, DWORD dwSize);
void Clear();
};
template <class T>
CRefSimpleDataBufferT<T>::CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize)
{
m_pData = const_cast<DataTypePointer>(pBuffer);
m_dwDataLen = dwSize;
}
template <class T>
void CRefSimpleDataBufferT<T>::Clear()
{
if (m_pData)
delete []m_pData;
m_pData = NULL;
m_dwDataLen = 0;
}
template <class T>
BOOL CRefSimpleDataBufferT<T>::SetData(typename CRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
{
Clear();
m_pData = const_cast<DataTypePointer>(pBuffer);
m_dwDataLen = dwSize;
return TRUE;
}
从实现的代码来看,如果引用的数据是动态分配的,就可以调用Clear函数释放内存,反之,则不需要调用。
5.自动数据引用类
自动数据引用类就是引用外部的动态分配的数据源,并自动释放这个数据源的内存。CAutoRefSimpleDataBufferT的实现代码如下:
//自动释放动态分配的数据引用类
template <class T>
class CAutoRefSimpleDataBufferT : public CRefSimpleDataBufferT<T>
{
public:
CAutoRefSimpleDataBufferT() { }
CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer);
void Clear();
DataTypePointer operator->() { return GetData(); }
ConstDataTypePointer operator->() const { return GetData(); }
virtual ~CAutoRefSimpleDataBufferT();
};
template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
: CRefSimpleDataBufferT<T>(pBuffer, dwSize)
{
}
template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer)
: CRefSimpleDataBufferT<T>(pBuffer, 1)
{
}
template <class T>
void CAutoRefSimpleDataBufferT<T>::Clear()
{
if (1 == m_dwDataLen)
delete m_pData;
else
CRefSimpleDataBufferT<T>::Clear();
}
template <class T>
CAutoRefSimpleDataBufferT<T>::~CAutoRefSimpleDataBufferT()
{
Clear();
}
CAutoRefSimpleDataBufferT和CRefSimpleDataBufferT的不同点就在于析构函数自动调用了Clear函数,释放了数据源的内存。
6.几种缓冲区的类关系图
7.注意事项
1)静态成员变量的初始化:静态成员变量需要在类外进行初始化,并且只能初始化一次。
2)线程安全:如果多个线程可能同时访问这个静态缓冲区,你需要实现适当的同步机制来避免数据竞争和不一致。
3)资源管理:静态缓冲区在程序结束时自动销毁,但如果你在其中存储了动态分配的资源(如指针指向的堆内存),你需要确保在程序结束前正确释放这些资源。
4)性能考虑:静态缓冲区大小固定,如果缓冲区大小设置不当,可能会导致频繁的内存溢出或内存浪费。
5)并发访问:在并发环境中,如果多个线程可能同时写入或读取缓冲区,需要考虑使用互斥锁(如std::mutex
)来同步访问。
8.完整代码
Noncopyable.h
/*************************************************************************
// 功能: 防止拷贝类
// 备注:
*************************************************************************/
#pragma once
class CNoncopyable
{
public:
CNoncopyable() {}
~CNoncopyable() {}
protected:
CNoncopyable(const CNoncopyable& src); //拷贝构造函数
const CNoncopyable& operator=(const CNoncopyable& src); //赋值函数
};
SimpleDataBuffer.h
#pragma once
#include "Noncopyable.h"
#include <assert.h>
#include <new>
#include <stdexcept>
using namespace std;
#define MAX_STATIC_SIMPLE_BUFFER_SIZE (4*1024) //4K
#define MAX_DYNAMIC_SIMPLE_BUFFER_SIZE (800*1024) //800K
template <class T>
class CSimpleDataBufferBase : public CNoncopyable
{
public:
typedef T DataType;
typedef T* DataTypePointer;
typedef T& DataTypeReference;
typedef const T ConstDataType;
typedef const T* ConstDataTypePointer;
typedef const T& ConstDataTypeReference;
public:
CSimpleDataBufferBase() {}
virtual ~CSimpleDataBufferBase() {}
public:
virtual DWORD GetSize() const = 0;
virtual DataTypePointer GetData() = 0;
virtual ConstDataTypePointer GetData() const = 0;
virtual DWORD GetMaxSize() const = 0;
operator DataTypePointer() { return GetData(); }
DataTypeReference operator*() { return *GetData(); }
DataTypeReference operator[](int nIndex);
virtual BOOL SetData(ConstDataTypePointer pData, DWORD dwSize) = 0;
virtual void SetSize(DWORD dwSize) = 0;
virtual void Clear() = 0;
};
template <class T>
typename CSimpleDataBufferBase<T>::DataTypeReference CSimpleDataBufferBase<T>::operator[](int nIndex)
{
if ( (nIndex >= 0) && (nIndex < (int)GetSize()))
{
DataTypePointer pData = GetData();
return pData[nIndex];
}
else
{
throw std::out_of_range("invalid data<nIndex> position");
}
}
//数据静态分配
template <class T>
class CStaticSimpleDataBufferT : public CSimpleDataBufferBase<T>
{
public:
CStaticSimpleDataBufferT(DWORD dwMaxSize = MAX_STATIC_SIMPLE_BUFFER_SIZE);
virtual ~CStaticSimpleDataBufferT() { }
public:
DWORD GetSize() const { return m_dwDataLen; }
DataTypePointer GetData() { return m_sData ;}
ConstDataTypePointer GetData() const { return m_sData ;}
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize);
void SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
DWORD GetMaxSize() const { return m_dwMaxDataSize; }
void Clear() { m_dwDataLen = 0; }
private:
DataType m_sData[MAX_STATIC_SIMPLE_BUFFER_SIZE];
DWORD m_dwDataLen;
const DWORD m_dwMaxDataSize;
};
template <class T>
CStaticSimpleDataBufferT<T>::CStaticSimpleDataBufferT(DWORD dwMaxSize)
: m_dwDataLen(0),
m_dwMaxDataSize(dwMaxSize)
{
}
template <class T>
BOOL CStaticSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
int i;
if (dwSize > m_dwMaxDataSize)
return FALSE;
for (i = 0; i < (int)dwSize; i++)
m_sData[i] = pData[i];
m_dwDataLen = dwSize;
return TRUE;
}
///
template <class T>
class CSimpleDataBufferAdapter : public CSimpleDataBufferBase<T>
{
public:
CSimpleDataBufferAdapter() : m_pData(NULL),m_dwDataLen(0) { }
virtual ~CSimpleDataBufferAdapter() { }
public:
DWORD GetSize() const { return m_dwDataLen; }
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize) { assert(0); return FALSE; }
void SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
DWORD GetMaxSize() const { assert(0); return 0; }
void Clear() { assert(0); }
DataTypePointer GetData() { return m_pData ;}
ConstDataTypePointer GetData() const { return m_pData ;}
protected:
DataTypePointer m_pData;
DWORD m_dwDataLen;
};
/
template <class T>
class CDynamicSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
CDynamicSimpleDataBufferT(DWORD dwMaxSize = MAX_DYNAMIC_SIMPLE_BUFFER_SIZE);
virtual ~CDynamicSimpleDataBufferT() { ClearData(); }
public:
void Clear() { m_dwDataLen = 0; }
DWORD GetMaxSize() const { return m_dwMaxDataSize; }
BOOL SetData(ConstDataTypePointer pData, DWORD dwSize);
protected:
void ClearData();
private:
const DWORD m_dwMaxDataSize;
};
template <class T>
CDynamicSimpleDataBufferT<T>::CDynamicSimpleDataBufferT(DWORD dwMaxSize)
: m_dwMaxDataSize(dwMaxSize)
{
m_pData = new T[dwMaxSize];
if (m_pData == NULL)
throw std:: bad_alloc("new T Array Failed");
m_dwDataLen = 0;
assert(m_pData != NULL);
assert(m_dwDataLen >= 0);
}
template <class T>
void CDynamicSimpleDataBufferT<T>::ClearData()
{
if (m_pData)
delete []m_pData;
m_pData = NULL;
m_dwDataLen = 0;
}
template <class T>
BOOL CDynamicSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
int i;
if (dwSize > m_dwMaxDataSize)
return FALSE;
for (i = 0; i < (int)dwSize; i++)
m_pData[i] = pData[i];
m_dwDataLen = dwSize;
return TRUE;
}
//
template <class T>
class CRefSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
CRefSimpleDataBufferT() { }
CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
virtual ~CRefSimpleDataBufferT() { }
public:
BOOL SetData(ConstDataTypePointer pBuffer, DWORD dwSize);
void Clear();
};
template <class T>
CRefSimpleDataBufferT<T>::CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize)
{
m_pData = const_cast<DataTypePointer>(pBuffer);
m_dwDataLen = dwSize;
}
template <class T>
void CRefSimpleDataBufferT<T>::Clear()
{
if (m_pData)
delete []m_pData;
m_pData = NULL;
m_dwDataLen = 0;
}
template <class T>
BOOL CRefSimpleDataBufferT<T>::SetData(typename CRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
{
Clear();
m_pData = const_cast<DataTypePointer>(pBuffer);
m_dwDataLen = dwSize;
return TRUE;
}
//自动释放动态分配的数据引用类
template <class T>
class CAutoRefSimpleDataBufferT : public CRefSimpleDataBufferT<T>
{
public:
CAutoRefSimpleDataBufferT() { }
CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer);
void Clear();
DataTypePointer operator->() { return GetData(); }
ConstDataTypePointer operator->() const { return GetData(); }
virtual ~CAutoRefSimpleDataBufferT();
};
template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
: CRefSimpleDataBufferT<T>(pBuffer, dwSize)
{
}
template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer)
: CRefSimpleDataBufferT<T>(pBuffer, 1)
{
}
template <class T>
void CAutoRefSimpleDataBufferT<T>::Clear()
{
if (1 == m_dwDataLen)
delete m_pData;
else
CRefSimpleDataBufferT<T>::Clear();
}
template <class T>
CAutoRefSimpleDataBufferT<T>::~CAutoRefSimpleDataBufferT()
{
Clear();
}