循环利用内存、环形缓冲区

备份两种重复利用内存,避免频繁申请内存的方法。

方法一:重复利用一块线性内存

DataBuffer.h

#ifndef DATABUFFER_H
#define DATABUFFER_H


#define BUFFER_SIZE  1024  //初始缓冲区大小

class DataBuffer
{
public:
    char *m_pBuffer;    //缓冲区
    int m_nBufferSize;  //缓冲区大小
    int m_nOffset;      //缓冲区中当前数据大小

    int  getDataLen();           //获得缓冲区中数据大小
    bool reBufferSize(int nLen); //调整缓冲区大小
    
    void reset();          //缓冲区复位
    void poll(int nLen);   //移除缓冲区首部的第一个数据包
	bool addMsg(char *pBuf, int nLen);  //添加消息到缓冲区
	void popMsg(char **pOutBuf, int nLen); //从缓冲区中取出数据   

 public:
    DataBuffer();
    ~DataBuffer();
};

#endif // DATABUFFER_H

DataBuffer.cpp

#include "databuffer.h"
#include "string.h"
#include <QException>


//构造
DataBuffer::DataBuffer()
{
    m_nBufferSize = BUFFER_SIZE;			  //缓冲区大小
    m_nOffset = 0;							  //缓冲区当前现有数据大小
    m_pBuffer = new char[m_nBufferSize];      //分配缓冲区
    memset(m_pBuffer, 0, sizeof(m_pBuffer));  //清空缓冲区
}

//析构
DataBuffer::~DataBuffer()
{
    delete [] m_pBuffer;  //释放缓冲区
    m_pBuffer = NULL;
    m_nBufferSize = 0;
    m_nOffset = 0;
}

//获得缓冲区中数据大小
int DataBuffer::getDataLen()
{
    return m_nOffset;
}

//重置缓冲区大小
bool DataBuffer::reBufferSize(int nLen)
{
    char *oBuffer = m_pBuffer;  //保存原缓冲区地址
    try
    {
        nLen = nLen < 64 ? 64: nLen;  //保证最小大小
        while(m_nBufferSize < nLen)
        {
            m_nBufferSize *= 2;
        }
        m_pBuffer = new char[m_nBufferSize]; //分配新缓冲区
        memset(m_pBuffer, 0, sizeof(m_pBuffer));
        memcpy(m_pBuffer, oBuffer, m_nOffset); //将原缓冲区中的内容拷贝到新缓冲区
        delete []oBuffer;  //释放原缓冲区
    }
    catch(QException e)
    {
        return false;
    }
    return true;
}

 /*
  *功  能:向缓冲区中添加消息
  *参  数:pBuf:要添加的数据
  *		   nLen:数据长度
  *返回值:成功失败
  */
bool DataBuffer::addMsg(char *pBuf, int nLen)
{
    try
    {
        if(m_nOffset + nLen > m_nBufferSize)        //如果缓冲过小,重新调整其大小
            reBufferSize(m_nOffset + nLen);

        memcpy(m_pBuffer + m_nOffset, pBuf, nLen);  //将新数据拷贝到缓冲区尾
        m_nOffset += nLen;  //修改数据偏移
    }
    catch(QException e)
    {
        return false;
    }
    return true;
}

/*
 *功  能:从缓冲区中取数据
 *参  数:pBuf:二级指针,用于保存取出的数据
 *		  nLen:要取的数据长度
 *返回值:无
 */
void DataBuffer::popMsg(char **pOutBuf, int nLen)
{
	if (nLen == 0 || nLen < 0 || m_nOffset == 0 || m_pBuffer == NULL || m_nOffset < nLen)
		return;

	if (m_nOffset >= nLen)
	{
		memcpy(pOutBuf, m_pBuffer, nLen);
	}
	poll(nLen);

}
//缓冲区复位
void DataBuffer::reset()
{
    if(m_nOffset > 0)
    {
        memset(m_pBuffer, 0, sizeof(m_pBuffer));
        m_nOffset = 0;
    }
}

//移除缓冲区首部第一个数据包
//nLen:一个数据包的大小
void DataBuffer::poll(int nLen)
{
    if(nLen == 0 || nLen < 0 || m_nOffset == 0 || m_pBuffer == NULL || m_nOffset< nLen)
        return;

   if(m_nOffset >= nLen)
   {
        memcpy(m_pBuffer, m_pBuffer + nLen, m_nOffset - nLen);
        m_nOffset -= nLen;
   }
}

方法二:环形缓冲区

DataBuffer.h

 #ifndef NETDATABUFFER_H
#define NETDATABUFFER_H

#define BUFFER_SIZE  1024  //初始缓冲区大小

class DataBuffer
{
public:
	char *m_pBuffer;    //缓冲区
	int m_nBufferSize;  //缓冲区大小
	int m_nStart;       //数据开始位置
	int m_nEnd;         //数据结束位置
	bool m_isFull;      //缓冲区是否已满
	bool m_isEmpty;     //缓冲区是否为空

	int getDataLen();				    //获得缓冲区中数据大小
	bool reBufferSize(int nLen);        //调整缓冲区大小
	void poll(int nLen);                //移除缓冲区首部的第一个数据包
	void reset();                       //缓冲区复位
	bool addMsg(char *pBuf, int nLen);  //添加消息到缓冲区
	void popMsg(char **pOutBuf, int nLen); //从缓冲区中取出数据   

public:
	DataBuffer();
	~DataBuffer();
};

#endif // NETDATABUFFER_H

DataBuffer.cpp

#include "databuffer.h"
#include "string.h"
//#include <QException>

//构造
DataBuffer::DataBuffer()
{
	m_nBufferSize = BUFFER_SIZE;				//缓冲区大小
	m_nStart = 0;								//数据开始位置
	m_nEnd = 0;									//数据结束位置
	m_isFull = false;							//缓冲区是否已满
	m_isEmpty = true;							//缓冲区是否为空
	m_pBuffer = new char[m_nBufferSize];        //分配缓冲区
	memset(m_pBuffer, 0, sizeof(m_pBuffer));    //清空缓冲区
}

//析构
DataBuffer::~DataBuffer()
{
	delete[] m_pBuffer;  //释放缓冲区
	m_pBuffer = NULL;
	m_nBufferSize = 0;
}

//获得缓冲区中数据大小
int DataBuffer::getDataLen()
{
	if (m_isFull)
	{
		return m_nBufferSize;
	}
	else if (m_nEnd < m_nStart)
	{
		return (m_nBufferSize - m_nStart) + m_nEnd;
	}
	else
	{
		return m_nEnd - m_nStart;
	}
}


//重置缓冲区大小
bool DataBuffer::reBufferSize(int nLen)
{
	char *oBuffer = m_pBuffer;  //保存原缓冲区地址

	nLen = nLen < 64 ? 64 : nLen;  //保证最小大小
	while (m_nBufferSize < nLen)
	{
		m_nBufferSize *= 2;
	}
	m_pBuffer = new char[m_nBufferSize]; //分配新缓冲区
	memset(m_pBuffer, 0, sizeof(m_pBuffer));

	//将原缓冲区中的内容拷贝到新缓冲区
	if (m_nStart < m_nEnd)
	{
		memcpy(m_pBuffer, oBuffer + m_nStart, m_nEnd - m_nStart);
	}
	else
	{
		int len1 = m_nBufferSize - m_nStart;
		memcpy(m_pBuffer, oBuffer + m_nStart, len1);
		memcpy(m_pBuffer + len1, oBuffer, m_nEnd);
	}

	delete[]oBuffer;  //释放原缓冲区

	return true;
}

/*
 *功  能:向缓冲区中添加消息
 *参  数:pBuf:要添加的数据
 *		   nLen:数据长度
 *返回值:无
 */
bool DataBuffer::addMsg(char *pBuf, int nLen)
{

	if (nLen == 0 || pBuf == NULL)
	{
		return false;
	}
	if (getDataLen() + nLen > m_nBufferSize)       //如果缓冲区过小,重新调整其大小
	{
		reBufferSize(getDataLen() + nLen);
		memcpy(m_pBuffer + m_nEnd, pBuf, nLen);   //将数据添加到缓冲区尾
		m_nEnd += nLen;
		m_isFull = m_nStart == m_nEnd;
	}
	else if (m_nStart <= m_nEnd)
	{
		int rightLen = m_nBufferSize - m_nEnd;    //缓冲区右半部分长度
		if (nLen <= rightLen)
		{
			memcpy(m_pBuffer + m_nEnd, pBuf, nLen);
			m_nEnd += nLen;
			m_isFull = m_nStart == m_nEnd;
		}
		else
		{
			int leftLen = nLen - rightLen;        //剩余数据长度
			memcpy(m_pBuffer + m_nEnd, pBuf, rightLen);
			memcpy(m_pBuffer, pBuf, leftLen);
			m_nEnd = leftLen;
			m_isFull = m_nStart == m_nEnd;
		}
	}
	else
	{
		memcpy(m_pBuffer + m_nEnd, pBuf, nLen);
		m_nEnd += nLen;
		m_isFull = m_nStart == m_nEnd;
	}
	m_isEmpty = false;

	return true;
}

//缓冲区复位
void DataBuffer::reset()
{
	if (!m_isEmpty)
	{
		memset(m_pBuffer, 0, sizeof(m_pBuffer));
		m_nStart = 0;
		m_nEnd = 0;
	}
}

/*
 *功  能:从缓冲区中取数据
 *参  数:pBuf:二级指针,用于保存取出的数据
 *		  nLen:要取的数据长度
 *返回值:无
 */
void DataBuffer::popMsg(char **pOutBuf, int nLen)
{
	if (m_isEmpty || getDataLen() < nLen  || nLen ==0 || nLen <0)
	{
		return;
	}
	if (m_nStart < m_nEnd)
	{
		memcpy(pOutBuf, m_pBuffer + m_nStart, nLen);
	}
	else
	{
		int rightLen;
		if (m_nStart == m_nEnd)
		{
			rightLen = m_nBufferSize - m_nEnd;    //缓冲区右半部分长度
		}
		else
		{
			rightLen = m_nBufferSize - m_nStart;  //右半部分数据长度
		}

		if (nLen <= rightLen)   //如果数据包大小 < 缓冲区右面的数据
		{
			memcpy(pOutBuf, m_pBuffer + m_nEnd, nLen);
		}
		else
		{
			int leftLen = nLen - rightLen;
			m_nStart = leftLen;
			memcpy(pOutBuf, m_pBuffer + m_nEnd, rightLen);
			memcpy(pOutBuf + rightLen, m_pBuffer, leftLen);
		}

	}
	poll(nLen);
}

//移除缓冲区首部第一个数据包
//nLen:一个数据包的大小
void DataBuffer::poll(int nLen)
{
	if (m_isEmpty || getDataLen() < nLen || nLen == 0 || m_pBuffer == NULL)
	{
		return;
	}

	if (m_nStart < m_nEnd)
	{
		m_nStart += nLen;
		m_isEmpty = m_nStart == m_nEnd;
	}
	else
	{
		int rightLen;
		if (m_nStart == m_nEnd)
		{
			rightLen = m_nBufferSize - m_nEnd;    //缓冲区右半部分长度
		}
		else
		{
			rightLen = m_nBufferSize - m_nStart;  //右半部分数据长度
		}

		if (nLen <= rightLen)   //如果数据包大小 < 缓冲区右面的数据
		{
			m_nStart += nLen;
			m_isEmpty = m_nStart == m_nEnd;
		}
		else
		{
			int leftLen = nLen - rightLen;
			m_nStart = leftLen;
			m_isEmpty = m_nStart == m_nEnd;
		}
	}
}

借鉴
https://blog.youkuaiyun.com/u012319493/article/details/52006940

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值