•   内存安全  

  在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. 再见了SpringMVC!这个框架有点厉害,甚至干掉了Servlet!

    # 前言 对 Java 开发者来说, Spring 发布 5.0 正式版,而新版 Spring 的一大特色,就是 Reactive Web 方案 Web Flux,这是用来替代 Spring Web ...

  2. 测试必备:jmeter测试http协议接口的各种传参方式

    测试接口,postman和jmeter是用得最频繁的工具,特别是jmeter,支持很多种协议,且除了测功能,还能做自动化测试和性能测试.下面主要介绍jmeter测试http协议接口的用法,包含get, ...

  3. 树莓派Raspberry Pi OS(原Raspbian)系统常用配置

    首次开机自动连接WIFI 在资源浏览器中打开刚写好Raspberry Pi OS(之前叫Raspbian)系统的SD卡,如果有boot目录则在boot目录中新建一个名为wpa_supplicant.c ...

  4. 【Unity 插件】Lean Pool 使用

    2020-09-11 Lean Pool 是一个轻量级的游戏对象池库,它可以轻松的帮助你的游戏提高性能.当然,Lean Pool也可以工作于普通的C#类. 目录: 1.Lean Pool使用 2.Le ...

  5. python中获取中位数

    普通方法: 对列表进行排序,然后根据长度为奇数或者偶数的不同情况计算中位数 def huahua(x): length = len(x) print(length) x.sort() print(x) ...

  6. 删除链表的倒数第N个节点(头部加一个哑结点)

    我的代码:测试用例[1,2]2,  时会报错,无法不能删除第一个指针 /** * Definition for singly-linked list. * public class ListNode ...

  7. 小白也能看懂的ArrayList的扩容机制

    来,话不多说进入正题!我们下面用最简单的代码创建ArrayList并添加11个元素,并 一 一 讲解底层源码:在说之前,给大家先普及一些小知识: >ArrayList底层是用数组来实现的 > ...

  8. C语言中的左移与右移 <<, >> 位运算

    这里参考了一篇很好的位运算,涉及到位运算可能会遇到的正负号问题,左右溢出怎么处理问题. 参考: 1. https://www.cnblogs.com/myblesh/articles/2431806. ...

  9. 【题解】SP1811 LCS - Longest Common Substring

    \(\color{purple}{Link}\) \(\text{Solution:}\) 题目要求找到两个串的最长公共子串.\(LCP\) 我们将两个串中间和末尾插入终止符,并弄到一棵后缀树上去. ...

  10. RESTfull是什么

    经常做接口测试,会看很多接口文档,那怎么识别研发的接口设计是否足够规范,是否符合一些行业标准或准则.那认识了解RESTfull,可以让我们更具有专业性.让我们对接口文档的阅.接口合理性设计识别,做到有 ...