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

枣庄网站建设电话搜索引擎排名google

枣庄网站建设电话,搜索引擎排名google,wordpress 3.4.2,什么网站做全景效果图好智能指针之shared_ptr与weak_ptr前言智能指针实例分析前言 C与其他语言的不同点之一就是可以直接操作内存,这是一把双刃剑,直接操作内存可以提高开发的灵活度,开发人员在合适的时机申请内存,在合适的时机释放内存,减少…

智能指针之shared_ptr与weak_ptr

    • 前言
    • 智能指针
    • 实例分析

前言

 C++与其他语言的不同点之一就是可以直接操作内存,这是一把双刃剑,直接操作内存可以提高开发的灵活度,开发人员在合适的时机申请内存,在合适的时机释放内存,减少冗余内存的占用,听起来非常不错。然而, 实际情况是申请了内存,忘记了释放,导致内存泄漏;又或者是,申请了内存,在某些情况下被释放了,然而另一部分代码却在继续使用这块内存,导致访问了非法内存,程序崩溃。当然,大部分的内存泄漏与访问非法内存导致的程序崩溃在debug版本中都是可以被发现的,但是还是会存在一些比较隐秘的角落,在测试期间发现不到,导致用户在试用期间发生崩溃,这是最糟的情况。

智能指针

 C++11的新特性之一就是增加了三组智能指针,shared_ptr,weak_ptr,unique_ptr,通过合理的使用者三组智能指针,可以极大的避免开发过程中有关内存的困扰。今天我们只介绍前两个。

shard_ptr是可以对引用进行计数的,当有其他地方引用该指针时,引用计数加1,当有地方释放该指针时,引用计数减一,只有当引用计数未0时,这个指针才会被真正的析构。

weak_ptr不会增加引用计数,它一般是与shard_ptr搭配使用,使用shared_ptr来构造weak_ptr,weak_ptr调用lock()方法,如果该shared_ptr已经被析构了,则返回null,如果还没被析构,则返回一个shared_ptr,并且该shared_ptr的引用计数加1。

 引用C++的经典书籍 **《Effective C++》**第三版中的一段话来感受下shared_ptr的优点

实际上,返回shard_ptr让接口设计者得以阻止一大群客户犯下资源泄漏的错误,因为就如条款14所言,shard_ptr允许当前智能指针被建立起来时指定一个资源释放函数(所谓删除其,“deleter”)绑定与智能指针身上。

shared_ptr有一个特别好的性质是:它会自动使用它的"每个指针专属的删除器",因而消除另一个潜在的客户错误:所谓的 “cross-DLL problem”。这个问题发生于“对象在动态链接程序库(DLL)中被new创建,却在另一个DLL内被delete销毁“。在许多平台上,这一类“跨DLL之new/delete成对运用”会导致运行期错误。 shared_ptr没有这个问题,因为它缺省的删除器是来自"shared_ptr诞生的那个DLL"的delete。

 在C++开发中,遇到的问题越多,越会觉得**《Effective C++》第三版**真是一本好书,全书55个条款,分为

  • 让自己习惯C++
  • 构造/析构/赋值运算
  • 资源管理
  • 设计与声明
  • 实现
  • 继承与面向对象设计
  • 模板与泛型编程
  • 定值new与delete
  • 杂项讨论

 这九大部分,每一项条款都直击问题要害,给出防范措施,搭配**《C++ Primer》**阅读,C++程序员必备!

 网上买**《Effective C++》加一本《C++ Primer》大概要100块钱,如果有需要的同学可以关注公众号程序员DeRozan**,回复1207直接领取。

 下面来通过一个实例来感受下智能指针。

实例分析

 下面我们通过分析一个例子,来大概感受下智能指针的好处。

 一个服务,会接收一个cmd以及其携带的参数,并将其存入一个任务队列,交给一个任务线程去处理。

 worker是一个对象,其有一个成员函数可以处理这个cmd。

 函数asyncTaskHandler将这个cmd的handler函数以及参数封装到一个结构体中,然后放入队列m_taskQue中,会有任务线程来取任务并执行。

 生产者

struct AICTask_t {int cmd;int task_id;taskStatus status;BaseWorker* worker;arg_t* arg;                  
};int AICTaskManager::asyncTaskHandler(int cmd, std::string &reqMsg, int reqMsgLen, std::string &respMsg, int &respMsgLen)
{TdInfo("AICTaskManager::asyncTaskHandler");TdInfo("create task");AICTask_t task;auto iter = m_workerMap.find(cmd); //m_workerMap : std::map<int, BaseWorker*> if(iter != m_workerMap.end()) {task->worker = iter->second;task->arg.cmd = cmd;task->arg.reqMsg = reqMsg;task->arg.reqMsgLen = reqMsgLen;task->arg.respMsg = respMsg;task->arg.respMsgLen = respMsgLen;task->status = prepare_to_start;}else{TdError("not found this cmd");return -1;}pthread_mutex_lock(&m_workerLock);while (m_taskQue.size() == m_maxQueSize && !m_stop){pthread_cond_wait(&m_cond_not_full, &m_workerLock);}m_taskQue.push(&task);  //std::queue<AICTask_t*> m_taskQue;m_taskMap[m_task_id]  = task;m_task_id++;pthread_mutex_unlock(&m_workerLock);pthread_cond_broadcast(&m_cond_not_empty);TdInfo("insert a task to queue");return 0;
}

 aicThreadHandle是任务线程的线程入口函数,负责将handler以及参数拿到,并执行。

 消费者

void *AICTaskManager::aicThreadHandle(void *arg)
{if(!arg) {TdError("bad parameter");return nullptr;}AICTaskManager *taskManager = (AICTaskManager *)arg;pthread_mutex_lock(&taskManager->m_workerLock);//loop for get task,every get lock, can get task while(true){// if m_taskQue not empty, get task, if empty, wait to get task// when task queue not empty, only one creater will wake up condition.while (taskManager->m_taskQue.empty() && !taskManager->m_stop){TdDebug("waiting to wake up");pthread_cond_wait(&taskManager->m_cond_not_empty, &taskManager->m_workerLock);// m_cond was waked up and get lock}//step while, now m_taskQue not emptyif (taskManager->m_stop){pthread_mutex_unlock(&taskManager->m_workerLock);TdInfo("thread % exit", pthread_self());pthread_exit(NULL);}AICTask_t* task = taskManager->m_taskQue.front();taskManager->m_taskQue.pop();pthread_mutex_unlock(&taskManager->m_workerLock);pthread_cond_broadcast(&taskManager->m_cond_not_full);TdInfo("exec function");task->status = running;(task->worker->handleCommand)(task->arg->cmd, task->arg->reqMsg, task->arg->reqMsgLen, task->arg->respMsg, task->arg->respMsgLen);task->status = over;}return nullptr;
}

 上述代码的逻辑很简单,简单的 生产者消费者模式,动态申请的内存全部使用的裸指针来保存,而且这个代码中有一个很明显的错误。

 生产者代码的第13行,AICTask_t task是在栈上申请的变量,存入std::queue<AICTask_t*> m_taskQue, m_taskQue内保存的是指针类型,所以在第34行通过取地址符传入了一个指针指向上的task,结果程序在消费者的第41行崩溃了。

 为什么会崩溃呢,原因就是生产者把指向task的指针放入任务队列后,函数就执行结束了,task是上的变量,随着程序结束就被释放了,然而,m_taskQue还保存着指向task的指针,指向了一块未初始化的内存。在任务处理函数中,这个指针被访问了,程序就崩溃了。

 为什么不在堆上申请task呢,因为我觉得在堆上申请还需要手动释放,容易出问题,所以想偷个懒,直接在栈上申请了,没有考虑到上面说的问题。

 消费者的代码中,对于裸指针都是直接访问的,也没有检查是不是已经被释放了。

 总之,手动管理内存实在太容易出问题了,所以,使用智能指针来管理内存,是很不错的选择。

 将上面的代码进行改造,将需要用到指针的地方改为shared_ptr,并使用weak_ptr来检查智能指针已经被析构。

 改造过后:

 生产者

int AICTaskManager::asyncTaskHandler(int cmd, std::string &reqMsg, int reqMsgLen, std::string &respMsg, int &respMsgLen)
{TdInfo("AICTaskManager::asyncTaskHandler");TdInfo("create task");std::shared_ptr<AICTask_t> task = std::make_shared<AICTask_t>();auto iter = m_workerMap.find(cmd);if(iter != m_workerMap.end()) {task->worker = iter->second;task->arg.cmd = cmd;task->arg.reqMsg = reqMsg;task->arg.reqMsgLen = reqMsgLen;task->arg.respMsg = respMsg;task->arg.respMsgLen = respMsgLen;task->status = prepare_to_start;}else{TdError("not found this cmd");return -1;}pthread_mutex_lock(&m_workerLock);while (m_taskQue.size() == m_maxQueSize && !m_stop){pthread_cond_wait(&m_cond_not_full, &m_workerLock);}m_taskQue.push(task);m_taskMap[m_task_id]  = task;m_task_id++;pthread_mutex_unlock(&m_workerLock);pthread_cond_broadcast(&m_cond_not_empty);TdInfo("insert a task to queue");return 0;
}

 消费者

void *AICTaskManager::aicThreadHandle(void *arg)
{if(!arg) {TdError("bad parameter");return nullptr;}AICTaskManager *taskManager = (AICTaskManager *)arg;pthread_mutex_lock(&taskManager->m_workerLock);//loop for get task,every get lock, can get task while(true){// if m_taskQue not empty, get task, if empty, wait to get task// when task queue not empty, only one creater will wake up condition.while (taskManager->m_taskQue.empty() && !taskManager->m_stop){TdDebug("waiting to wake up");pthread_cond_wait(&taskManager->m_cond_not_empty, &taskManager->m_workerLock);// m_cond was waked up and get lock}//step while, now m_taskQue not emptyif (taskManager->m_stop){pthread_mutex_unlock(&taskManager->m_workerLock);TdInfo("thread % exit", pthread_self());pthread_exit(NULL);}// std::weak_ptr<AICTask_t> task = taskManager->m_taskQue.front();std::shared_ptr<AICTask_t> task = std::weak_ptr<AICTask_t>(taskManager->m_taskQue.front()).lock();if(!task){TdError("expired task");return nullptr;}taskManager->m_taskQue.pop();pthread_mutex_unlock(&taskManager->m_workerLock);pthread_cond_broadcast(&taskManager->m_cond_not_full);TdInfo("exec function");task->status = running;std::shared_ptr<BaseWorker> worker = std::weak_ptr<BaseWorker>(task->worker).lock();if (!worker){TdError("worker expired");return nullptr;}(worker->handleCommand)(task->arg.cmd, task->arg.reqMsg, task->arg.reqMsgLen, task->arg.respMsg, task->arg.respMsgLen);task->status = over;}return nullptr;
}

 这样,我们在使用shared_ptr前,先通过weak_ptr判断是够可用,然后使用完成后,该指针会自动将引用计数减一,等到引用计数未0,也就是没有任何地方再引用它,就可以释放它指向的那块内存了。

不过需要注意的是,shard_ptr一定要用make_shared来构造,虽然有时携程shared_ptr<T>(new T())也能通过编译,但是这是会导致内存泄漏的。

 智能指针的用法非常多,本文讲的是最常见的一种情况,其他更复杂的用法,则需要继续学习与发现。

http://www.mmbaike.com/news/60387.html

相关文章:

  • 做视频图片博客网站什么是竞价推广
  • 网站建设 顺德百度指数使用方法
  • 网站关键词价格上海企业优化
  • 免费的公文写作网站个人如何加入百度推广
  • Wix做的网站在国内打不开电商营销
  • 网站制作是不是要一个后台怎么去推广自己的店铺
  • 重庆网站仿站微信营销方式
  • 网站建设设计规划佛山seo网站排名
  • 芜湖网站建设求职简历付费推广有几种方式
  • 北京海淀区政府网站湘潭网站设计外包服务
  • 邢台企业做网站营销策略有哪些
  • 科普文章在那个网站做信息流推广渠道有哪些
  • 遇到灾难网站变灰怎么做营销技巧和营销方法培训
  • 高端大气企业网站模板论文收录网站
  • 大连建设网站制作如何找友情链接
  • vs做的网站案例今日新闻头条新闻摘抄
  • 医保局网站建设武汉seo 网络推广
  • 电子商务网站建设选择服务器要考虑的因素有杭州百度优化
  • 洛阳网站制作哪家好南京seo优化培训
  • 海南响应式网站建设方案seo站长网
  • 杭州网站优化多少钱最佳磁力搜索天堂
  • 卫计局网站建设工作总结seo优化评论
  • 企业如何完善网站内容建设哈尔滨seo网站管理
  • 天津学网站建设单页应用seo如何解决
  • 武汉网站制作公司排名2021年最为成功的营销案例
  • 做公司点评的网站百度搜索推广是什么
  • 北戴河网站建设亚马逊关键词排名提升
  • wordpress 修改widget南京搜索引擎推广优化
  • 网站建设方案报价表短视频搜索seo
  • 西安 网站建设seo技术专员招聘