用auto_ptr类模板帮助动态内存管理
void g() //可能掷出
{
if (some_condition == false)
throw X();
} void func()
{
string * pstr = new string;
g(); //如果 g 掷出一个异常,内存溢出
delete pstr; //如果 g 掷出一个异常,则此行为不能达到的代码行。
}
int main()
{
try
{
func();
}
catch(...)
{}
}
当 g 掷出一个异常,异常处理机制展开堆栈:g()退出,同时控制被转移到 main() 的 catch(...)代码块。这时,无论怎样,func()中的delete语句都不会被执行,由此导致pstr的内存溢出。要是使用局部自动串变量,而不是使用动态分配-内存溢出就不会出现了:
string str; //局部自动对象
g(); //没有内存溢出
许多数据重要的结构以及应用,象链表,STL容器,串,数据库系统以及交互式应用必须使用动态内存分配,因此仍然冒着万一发生异常导致内存溢出的风险。C++标准化委员会意识到了这个漏洞并在标准库中添加了一个特殊的类模板,它就是std::auto_ptr,其目的是促使动态内存和异常之前进行平滑的交互。Auto_ptr保证当异常掷出时分配的对象(即:new操作符分配的对象)能被自动销毁,内存能被自动释放。下面我们就来讨论使用动态内存时,如何正确和有效地使用auto_ptr来避免资源溢出。这个技术适用于文件,线程,锁定以及与此类似的资源。
Auto_ptr的定义可以在<memory.h>中找到。与标准库中其它的成员一样,它被声明在命名空间std::中。当你实例化auto_ptr对象时,对它进行初始化的方法是用一个指针指向动态分配的对象,下面是实例化和初始化auto_ptr对象的例子:
#include <memory>
#include <string>
using namespace std;
void func()
{
auto_ptr<string> pstr (new string); /* 创建并初始化auto_ptr */
}
auto_ptr后面的尖括弧里指定auto_ptr指针的类型,在这个例子中是string。然后auto_ptr句柄的名字,在这个例子中是pstr。最后是用动态分配的对象指针初始化这个实例。注意你只能使用auto_ptr构造器的拷贝,也就是说,下面的代码是非法的:
auto_ptr<string> pstr = new string; //编译出错
Auto_ptr是一个模板,因此它是完全通用的。它可以指向任何类型的对象,包括基本的数据类型:
auto_ptr<int> pi (new int);
一旦你实例化一个auto_ptr,并用动态分配的对象地址对它进行了初始化,就可以将它当作普通的对象指针使用,例如:
*pstr = "hello world"; //赋值
pstr->size(); //调用成员函数
之所以能这样做是因为auto_ptr重载了操作符&,*和->。不要被语法误导,记住pstr是一个对象,不是一个指针。
auto_ptr是如何解决前面提到的内存溢出问题呢?auto_ptr的析构函数自动摧毁它绑定的动态分配对象。换句话说,当pstr的析构函数执行时,它删除构造pstr期间创建的串指针。你绝不能删除auto_ptr,因为它是一个本地对象,它的析构函数是被自动调用的。让我们看一下函数func()的修订版本,这次使用了auto_ptr:
void func()
{
auto_ptr<string> pstr (new string);
g(); //如果g()掷出异常,pstr 被自动摧毁
}
C++保证在堆栈展开过程中,自动存储类型的对象被自动摧毁。因此,如果g()掷出异常,pstr的析构函数将会在控制被转移到catch(...)块之前执行。因为pstr的析构函数删除其绑定的串指针,所以不会有内存溢出发生。这样我们在使用动态分配对象时,利用auto_ptr就实现了自动和安全的本地对象。
如何避免使用auto_ptr的缺陷
auto_ptr并不是完美无缺的,它的确很方便,但也有缺陷,在使用时要注意避免。首先,不要将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果(在另文中讨论)。
auto_ptr的另一个缺陷是将数组作为auto_ptr的参数:
auto_ptr<char> pstr (new char[12] ); //数组;为定义
记住不管什么时候使用数组的new操作时,必须要用delete[]来摧毁数组。因为auto_ptr的析构函数只对非数组类型起作用。所以数组是不能被正确摧毁的话,程序的行为是不明确的。总之,auto_ptr控制一个由new分配的单对象指针,仅此而已。
用auto_ptr类模板帮助动态内存管理的更多相关文章
- C++动态内存管理之shared_ptr、unique_ptr
C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...
- C++动态内存管理与源码剖析
引言 在本篇文章中,我们主要剖析c++中的动态内存管理,包括malloc.new expression.operator new.array new和allocator内存分配方法以及对应的内存释放方 ...
- c++动态内存管理与智能指针
目录 一.介绍 二.shared_ptr类 make_shared函数 shared_ptr的拷贝和引用 shared_ptr自动销毁所管理的对象- -shared_ptr还会自动释放相关联对象的内存 ...
- (原创)动态内存管理练习 C++ std::vector<int> 模拟实现
今天看了primer C++的 “动态内存管理类”章节,里面的例子是模拟实现std::vector<std::string>的功能. 照抄之后发现编译不通过,有个库函数调用错误,就参考着自 ...
- uCGUI动态内存管理
动态内存的堆区 /* 堆区共用体定义 */ typedef union { /* 可以以4字节来访问堆区,也可以以1个字节来访问 */ ]; /* required for proper aligne ...
- Keil C动态内存管理机制分析及改进(转)
源:Keil C动态内存管理机制分析及改进 Keil C是常用的嵌入式系统编程工具,它通过init_mempool.mallloe.free等函数,提供了动态存储管理等功能.本文通过对init_mem ...
- FreeRTOS 动态内存管理
以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...
- C++程序设计入门 引用和动态内存管理学习
引用: 引用就是另一个变量的别名,通过引用所做的读写操作实际上是作用于原变量上. 由于引用是绑定在一个对象上的,所以定义引用的时候必须初始化. 函数参数:引用传递 1.引用可做函数参数,但调用时只需 ...
- 动态内存管理详解:malloc/free/new/delete/brk/mmap
c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, calloc/realloc 上述8个函数/操作符是c/c++语言里常用来做动 ...
随机推荐
- AJAX JQuery 调用后台方法返回值(不刷新页面)
AJAX JQuery 调用后台方法返回值(不刷新页面) (1)无参数返回值(本人亲试返回结果不是预期结果) javascript方法: $(function () { //无 ...
- [转]struct 用法深入探索
struct用法深入探索 作者: Cloudward 1. struct的巨大作用 面对一个人的大型C/C++程序时,只看其对struct的使用情况我们就可以对其编写者的编程经验进行评估.因为一个大型 ...
- 修改SlidingMenu,使其能够完美运行
今天想给项目添加一个侧边栏的效果,使用到了https://github.com/jfeinstein10/SlidingMenu这个开源项目.项目本身可以通过github下载.此项目同时又依赖于一个名 ...
- 《Linux 设备驱动程序》读后感。 并发,竞态,死锁。
1. 概念 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. 来源: 1. Linux ...
- javascript中的继承方法
从Javascript面向对象编程(二):构造函数的继承这里,可以看到详细的说明. 我只是将其中的例子做成html文件,便于调试罢了. 1. 构造函数绑定 <html> <head& ...
- 基于eclipse的mybatis映射代码自动生成的插件http://blog.csdn.net/fu9958/article/details/7521681
基于eclipse的mybatis映射代码自动生成的插件 分类: JAVA 数据库 工具相关2012-04-29 00:15 2157人阅读 评论(9) 收藏 举报 eclipsegeneratori ...
- mysql主从切换步骤
1> 正常切换 1)从server检查SHOW PROCESSLIST语句的输出,直到你看到Has read all relaylogwaiting for the slave I/O th ...
- java写文件时,输出不完整的原因以及解决方法
在java的IO体系中,写文件通常会用到下面语句 BufferedWriter bo=new BufferedWriter(new FileWriter("sql语句.txt")) ...
- 使用 AngularJS 从零构建大型应用
0.导言 1.准备工作 2.构建框架 3.丰富你的directives 4.公用的services 5.用controllers组织业务 导言 纵览线上各种AngularJS教程,大部分都是基础与一些 ...
- JavaScript之JS实现动画效果
在前面的随笔中介绍了如何用DOM技术修改文档的央样式信息,用JavaScript添加样式信息可以节约我们的时间和精力,但总的来说,CSS仍是完成这类任务的最佳工具.但是有一个应用领域是目前的CSS无能 ...