C++ 智能指针(一)
内存安全
在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操作,那么另一个指针再执行别的操作会怎样?程序会发生段错误。要避免这个问题,可以用下面这些方案:
- 定义赋值运算符函数,进行深拷贝,这样的操作会使上面的两个指针不再指向同一个对象,缺点是浪费空间,所以智能指针都未采用此方案
- "独占"所指的对象;对于特定的对象,某一时刻只能有一个指针指定一个给定对象,当指针被销毁时,它所指的对象也被销毁,这就是用于auto_ptr和uniqiie_ptr 的策略,但unique_ptr的策略更严格。
- 利用引用计数,创建记录型的指针;例如,赋值时,计数将加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++ 智能指针(一)的更多相关文章
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- C++ 引用计数技术及智能指针的简单实现
一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...
- C++11智能指针读书笔记;
智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
随机推荐
- Linux常用命令详解(3)
pidofpstopipuptimewgetcurltrddtargrepfind 命令详解 1.pidof 获取正在运行程序的PID 实例1: [root@ken ~]# pidof sshd 24 ...
- 【Jenkins】三、设置定时任务
1.点击工程(Test1), 选择左侧的配置 2.选择"构建触发器"下面的"定时构建" 3.填写定时规则(这里设置每隔30分钟执行一次) 4.定时规则语法字段 ...
- 利用Python爬取疫情数据并使用可视化工具展示
import requests, json from pyecharts.charts import Map, Page, Pie, Bar from pyecharts import options ...
- PostGreSQL不同索引类型(btree & hash)的性能问题
在关系型数据库调优中,查询语句涉及到的索引类型是不得不考虑的一个问题.不同的类型的索引可能会适用不同类型的业务场景.这里我们所说的索引类型指的是访问方法(Access Method),至于从其他维度区 ...
- Java List 常用集合 ArrayList、LinkedList、Vector
Java 中的 List 是非常常用的数据类型.List 是有序的 Collection,Java List 一共有三个实现类,分别是:ArrayList.Vector.LinkedList 本文分析 ...
- WPF启动流程-自己手写Main函数
WPF一般默认提供一个MainWindow窗体,并在App.Xaml中使用StartupUri标记启动该窗体.以下通过手写实现WPF的启动. 首先先介绍一下VS默认提供的App.Xaml的结构,如下图 ...
- Lua设计与实现--读书笔记
目录 lua简介 一种通用的数据类型:lua_TValue 字符串 Table lua实现一个队列 lua简介 C++底层核心模块,暴露核心接口给lua脚本层,网络的收发都在c++层完成,本书简述lu ...
- Java基于POI实现excel任意多级联动下拉列表——支持从数据库查询出多级数据后直接生成【附源码】
Excel相关知识点 (1)名称管理器--Name Manager [CoderBaby]首先需要创建多个名称(包含key及value),作为下拉列表的数据源,后续通过名称引用.可通过菜单:&quo ...
- py004.python的逻辑运算,随机数及判断语句if,elif,else
判断语句又称 "分支语句" if判断语句的格式: if 条件1: 条件1满足时,执行的代码 -- # 前面有缩进4个空格 elif 条件2: 条件2满足时,执行的代码 -- # 前 ...
- Leetcode-dfs & bfs
102. 二叉树的层次遍历 https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 给定一个二叉树,返回其按层次遍历的节 ...