•   内存安全  

  在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象来进行初始化;delete,接收一个动态对象的指针,销毁该对象,并释放与之关联的内存。

  动态内存的使用很容易出问题,因为确保在正确的时间释放内存是及其困难的。有时我们会忘记释放内存(或程序抛出异常),在这种情况下就会产生内存泄漏;有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针(段错误)。

  下面写个Demo测试程序  

#include <memory>
#include <exception>
#define FLAG 3 //用于编译不同的程序 class Demo1
{
public:
Demo1()
{
std::cout << "Demo1" << std::endl;
} ~Demo1()
{
std::cout << "~Demo1" << std::endl;
}
}; bool throw_test(bool flag)
{
if (flag)
{
throw "throw_test";
} return flag;
} int main(int argc, char* argv[])
{
Demo1 *pDemo1 = new Demo1(); #if (FLAG == 1)
throw_test(true);  //1.执行这条语句,会打印~Demo1?
#endif #if (FLAG == 2)
try
{
throw_test(true);
}
catch (...) //2....代表捕获所有异常
{
delete pDemo1; //3.执行这条语句,会打印~Demo1?
throw;
}
#endif #if (FLAG == 3)
delete pDemo1;
#endif return 0;
}

  上述程序结果如下:

   当宏FLAG为1时,执行throw_test(true),即使程序抛出异常,它没有打印~Demo1;

  当宏FLAG为2时,执行throw_test(true),程序会抛出异常,之后捕获到异常打印~Demo1;

  当宏FLAG为3时,执行delete pDemo1,这是正常操作,程序会调用Demo1的析构函数,打印~Demo1;

  • 智能指针

  C++中的智能指针类型有:auto_ptr,shared_ptr,unique_ptr,weak_ptr(后三者为C++11新增的),它们均为类模板,使用需要包含<memory>头文件

  常规指针带来的风险

Demo1* pDemo1 = new Demo1();
Demo1* pDemo2;
pDemo2 = pDemo1;
printf("pDemo1:%x pDemo2:%x\n", pDemo1, pDemo2); 

  上面的pDemo1和pDemo2是常规指针,指向同一个对象(浅拷贝),因此打印的地址也是一样的;请试想一下如果其中一个指针执行了delete操作,那么另一个指针再执行别的操作会怎样?程序会发生段错误。要避免这个问题,可以用下面这些方案:

  1. 定义赋值运算符函数,进行深拷贝,这样的操作会使上面的两个指针不再指向同一个对象,缺点是浪费空间,所以智能指针都未采用此方案
  2. "独占"所指的对象;对于特定的对象,某一时刻只能有一个指针指定一个给定对象,当指针被销毁时,它所指的对象也被销毁,这就是用于auto_ptr和uniqiie_ptr 的策略,但unique_ptr的策略更严格。
  3. 利用引用计数,创建记录型的指针;例如,赋值时,计数将加1,而指针过期时,计数将减1。当减为0时才调用delete。这是shared_ptr采用的策略。

  在C++11中,auto_ptr已弃用;编写一段测试程序,Demo1类还是使用上面定义的。

int main(int argc, char *argv[])
{
std::auto_ptr<Demo1> pDemo1(new Demo1);
std::auto_ptr<Demo1> pDemo2;
pDemo2 = pDemo1;
printf("pDemo1:%p pDemo2:%p\n", pDemo1, pDemo2);  //运行到这里pDemo1会打印什么?
return 0;
}

  上面的程序运行后,打印pDemo1的地址为NULL。具体可以查看下auto_ptr的赋值运算符的实现是如何的。

  下面这两张截图是VS2015下的auto_ptr的赋值运算符的实现;我们可以看到使用赋值运算符时,会调用reset函数,这是会将_Myptr的内存delete,并将地址置为NULL;如果pDemo1调用成员函数,此时会发送什么?

                  

   

  

  auto_ptr存在内存崩溃的风险,这个或许就是auto_ptr被C++11弃用的原因吧。

  未完待续...

C++ 智能指针(一)的更多相关文章

  1. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  2. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  3. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  4. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  7. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  8. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

  9. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  10. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

随机推荐

  1. Burger King使用RayOnSpark进行基于实时情景特征的快餐食品推荐

    作者:Luyang Wang, Kai Huang, Jiao Wang, Shengsheng Huang, Jason Dai 基于深度学习的推荐模型已广泛应用于各种电商平台中,为用户提供推荐.目 ...

  2. 利用Node实现HTML5离线存储

    前言 支持离线Web应用开发是HTML5的一个重点.离线Web应用就是在设备不能上网的时候仍然可以运行的应用.开发离线Web应用需要几个步骤,其中一个就是离线下必须能访问一定的资源(图像 JS css ...

  3. 每日爬虫JS小逆之5分钟旅游网MD5一锅端

    来吧骚年,每天花5分钟锻炼一下自己的JS调试也是极好的,对后期调试滑块验证码还原.拖动很有帮助,坚持下去,我们能赢.建议亲自试试哦,如果对大家有帮助的话不妨关注一下知识图谱与大数据公众号,当然不关注也 ...

  4. 新手学习Python第三方包库pip安装失败总结

    这篇文章纯原创,是之前自己学习使用pyhton时遇到的问题,故在此记录一下. 问题与需求:用python下载第三方库或包的时候出错怎么办? 方法有一下三种,可以解决大部分的问题. 1.在cmd命令控制 ...

  5. 深入解析Vue里函数的调用顺序介绍

    今天为大家分享一篇对vue里函数的调用顺序介绍,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. method用来定义方法的,比如你@click=& ...

  6. idea如何通过数据库生成实体类

    ---恢复内容开始--- https://blog.csdn.net/liu_yulong/article/details/72910588 ---恢复内容结束---

  7. Python-迭代协议-__iter__ __next__ iter next yield

    iter 本质是for循环调用的实质,for循环通过调用这个函数返回可迭代对象生成器形式,开始迭代取值捕获StopIteration错误退出循环 for循环首先找__iter__方法,然后再找 __g ...

  8. Centos-配置网络或显示当前网络接口状态-ifconfig

    ifconfig 配置网络或显示当前网络接口状态,必须由root用户执行 相关选项 -a 显示所有网络接口信息,包括活动或非活动 -s 显示活动接口简要信息 -v 如果网卡接口出现错误则返回错误信息 ...

  9. 【Python】数字与运算符

    数据类型与运算符 数字 / 浮点除 // 整数除 ** 乘方 多种混合类型运算数的运算会把整数转换为浮点数 除了 int 和 float,Python也支持其他类型的数字,例如 Decimal 或者 ...

  10. P1879 [USACO06NOV] Corn Fields G

    题目描述 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他 ...