C++新特性之右值引用&&的使用示例

今天在项目中遇到了一个新的优化方案,算记录个人成长吧
代码大概如下:

// 实现通用库定义函数
//后面的类很多都是继承自这些虚基类

    /*
    * @brief 设备操作回调接口
    */
    class IDeviceOperCB
    {
    public:
        /*! IDeviceOperCB::OnReadResult
        * @brief 读回调数据
        * @param nHandle 操作句柄,确定任务唯一性   主动操作返回非0值,代码内部自动添加返回默认值0
        * @param nErrCode 操作结果 0 表示成功 其他为错误码
        * @param pBuff  数据地址
        * @param nLen 数据长度
        * @return 成功返回0
        */
        virtual int onReadData(int nHandle, int nErrCode, char* pBuff, long nLen) = 0;
        ......
    };
   
    /*
    * @brief 设备操作接口
    */
    class IDeviceOper
    {
    public:
        /*! IDeviceOper::setCallback
        * @brief 操作回调接口
        */
        virtual bool setCallback(IDeviceOperCB *pCB) = 0;
        ......
    };

    /*
    * @brief 设备接口
    */
    class IDevice
    {
    public:
    /*! IDevice::open
    * @brief 打开设备
    * @param szAddr 设备地址连接字符串
    * @return 成功返回0,失败返回错误码
    */
    virtual int open(const char* szAddr) = 0;
    };

//实现类CDevConnBE.h

//优化前代码
#include <vector>
using std::vector;
#include <deque>

class IDevice;
class IDeviceOper;
class IDeviceOperCB; 
namespace std { class mutex; }
class CDevOperCallback;

class CDevConnBE
{
...
public:
    /*! CDevConnBE::pushData
    * @brief 写入数据
    * @param data 传入数据
    */
    void pushData(vector<unsigned char> &data);
  
 private:
    IDevice* m_pDevice;    // 设备接口
    CDevOperCallback* m_pDevOperCB;	// 用于实现函数回调的类
    std::deque<vector<unsigned char> > m_qDevData;
    std::mutex* m_pMutex;
}

//实现类CDevConnBE.cpp

#include "CDevConnBE.h"
#include "devimpif.h"	//最上面那个通用库定义文件名称
#include <mutex>
#include <string>

class CDevOperCallback :public GCSoft::IDeviceOperCB
{
public:
    CDevOperCallback(CDevConnBE *DevConnBE) { m_pDevConnBE = DevConnBE; }
    
public:
    virtual int onReadData(int nHandle, int nErrCode, char* pBuff, long nLen)
    {
    	std::string data = string(pBuff,nLen);	// 此处进行了第一次拷贝
        vector<unsigned char> vData;
        vData.assign(data.begin(), data.end());	// 第二次拷贝
        m_pDevConnBE->pushData(vData);	// 进行了第三次拷贝
        return 0;
    }
    virtual int onWriteData(int nHandle, int nErrCode) { return 0; }
private:
    CDevConnBE *m_pDevConnBE;
};

//CDevConnBE的类实现
CDevConnBE::CDevConnBE(const string& sConnInfo)
    : m_pDevice(0)
    , m_pDevOperCB(NULL)
    , m_pDevOper(NULL)
    , m_pMutex(0)
{
    m_pMutex = new std::mutex;
    ....
    start();
}

void CDevConnBE::start()
{
    if (NULL != m_pDevice){	// 构造函数中进行了赋值实现
        m_pDevOper = m_pDevice->devOper();
        
    	m_pDevOperCB = new CDevOperCallback(this);
    	m_pDevOper->setCallback(m_pDevOperCB);
    	m_pDevice->open(m_sConnInfo.c_str());// 使用连接信息Open
    }
}

void CDevConnBE::pushData(vector<unsigned char> &data)
{
    std::lock_guard<std::mutex> iLocker(*m_pMutex);
    if (data.size() > 0) {
        m_qDevData.push_back(data);	// 第四次拷贝
    }
}

负责与CDevConnBE模块实现对接的子模块

CSerialDevice .h

class CSerialDevice : public IDevice
{
public:
    CSerialDevice(void);
    ~CSerialDevice(void);

public:
virtual int open(const char* szAddr);	// 继承接口,负责打开设备(串口)
....
};

CSerialOper .h

class CSerialOper : public IDeviceOper
{
public:
    CSerialOper(CSerialDevice *device);
    ~CSerialOper();

public:
    /*! CDeviceOper::EventCallback
    * @brief 注册异步事件回调
    */
    virtual bool setCallback(IDeviceOperCB *pCB);
    ....
private:
    IDeviceOperCB *m_pCB;   // 事件回调接口
    ....
};

CSerialOper .cpp

....
bool CSerialOper::setCallback(IDeviceOperCB *pCB)
{
    if (m_pCB != NULL)
        return false;
    m_pCB = pCB;
    return true;
}

int CSerialOper::performRead(unsigned int size)
{
    ...
     m_pCB->onReadData(m_iHandle, FAILCODE, (char*)reMSG.c_str(), reMSG.size()); // 此处进行调用,使数据回调到CDevConnBE的CDevOperCallback ,使onReadData被触发
    ...
}
....

上面代码是工作写的代码,下面的优化代码是导师给我提醒的,说拷贝太多的话,数据量一多代码效率会变得很低。算工作中的成长吧.

CDevConnBE 优化代码

CDevConnBE.h

class CDevConnBE
{
public:
    CDevConnBE(const string& sConnInfo);
    ~CDevConnBE();
    
public:
   /*! CDevConnBE::pushData
    * @brief 写入数据
    * @param data 传入数据
    */
    void pushData(vector<unsigned char>&& data); // 使用右值引用
    ....
};

CDevConnBE.cpp

#include "CDevConnBE.h"
#include "devimpif.h"	//最上面那个通用库定义文件名称
#include <mutex>
#include <string>

class CDevOperCallback :public GCSoft::IDeviceOperCB
{
public:
    CDevOperCallback(CDevConnBE *DevConnBE) { m_pDevConnBE = DevConnBE; }
    
public:
    virtual int onReadData(int nHandle, int nErrCode, char* pBuff, long nLen)
    {
    	// 拷贝次数会大大减少
    	vector<unsigned char> vData;
        vData.insert(vData.end(), pBuff, pBuff + nLen);
        m_pDevConnBE->pushData(std::move(vData));
        return 0;
    }
    virtual int onWriteData(int nHandle, int nErrCode) { return 0; }
private:
    CDevConnBE *m_pDevConnBE;
};

//CDevConnBE的类实现
void CDevConnBE::CDevConnBE(const string& sConnInfo)
    : m_pDevice(0)
    , m_pDevOperCB(NULL)
    , m_pDevOper(NULL)
    , m_pMutex(0)
{
    m_pMutex = new std::mutex;
    ....
    start();
}

void CDevConnBE::start()
{
    if (NULL != m_pDevice){	// 构造函数中进行了赋值实现
        m_pDevOper = m_pDevice->devOper();
        
    	m_pDevOperCB = new CDevOperCallback(this);
    	m_pDevOper->setCallback(m_pDevOperCB);
    	m_pDevice->open(m_sConnInfo.c_str());// 使用连接信息Open
    }
}

void CDevConnBE::pushData(vector<unsigned char> &data)
{
    std::lock_guard<std::mutex> iLocker(*m_pMutex);
    if (data.size() > 0) {
        m_qDevData.push_back(std::move(data)); // 使用move代替拷贝
    }
}

大概就是这样,懒得细化了。大概的简化示例就是这样了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值