当前位置: 首页 > article >正文

C++简单缓冲区类设计

目录

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.动态缓冲区

        动态缓冲区类通常基于动态内存分配(如newdelete)来满足用户的需求。静态缓冲区的大小在编译时确定,而动态缓冲区的大小则根据需要动态变化。静态缓冲区适用于那些大小已知且不会改变的场景,而动态缓冲区则更灵活,适用于大小可能变化的场景。动态缓冲区类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();
}

http://www.kler.cn/a/322253.html

相关文章:

  • 用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转(跨文件跳转)这些功能
  • Java 核心技术卷 I 学习记录八
  • 《设计模式》创建型模式总结
  • 初学者编程语言的选择
  • 基于差分、粒子群算法下的TSP优化对比
  • 表格的选择弹窗,选中后返显到表格中
  • [数据结构] 二叉树题目 (二)
  • AI智能时代:哪款编程工具让你的工作效率翻倍?
  • C++(9.25)
  • mysql笔记—sql性能分析
  • C#的结构体(Struct)应用示例
  • BUG——IMX6ULL编译正点原子Linux内核报错
  • QMT如何获取股票基本信息?如上市时间、退市时间、代码、名称、是否是ST等。QMT量化软件支持!
  • 基于SSM+小程序的医院挂号登录管理系统(医院4)(源码+sql脚本+视频导入教程+文档)
  • 一六九、go使用泛型封装一个可以应用于任何字段的模糊匹配
  • 【C/C++】速通涉及string类的经典编程题
  • Redis的数据类型和编码方式
  • uniapp实现图片上下浮动效果
  • 多速率信号处理-半带滤波器
  • 【漏洞复现】灵当CRM multipleUpload.php接口处存在文件上传漏洞
  • 高通Android 12 push framework.jar和service.jar
  • VMware Tools安装——VMware Tools是灰色的,不能安装, (不带图形化界面的虚拟机,只有命令行的模式!!!)
  • 【网络底层原理】I/O多路复用技术select、poll和epoll详解与比较
  • uniapp微信小程序遮罩层u-popup禁止底层穿透
  • 如何延长变阻器的使用寿命?
  • 【解密 Kotlin 扩展函数】扩展函数的底层原理(十八)