动态内存使用最多的是在C++应用程序的代码中。有过编程经验的程序员虽然都知道new操作符的使用一定要与delete匹配,在某些场合仍然可能有内存溢出。当异常被掷出时,程序的正常控制流程被改变,因此导致潜在的内存溢出。例如,
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类模板帮助动态内存管理的更多相关文章

  1. C++动态内存管理之shared_ptr、unique_ptr

    C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...

  2. C++动态内存管理与源码剖析

    引言 在本篇文章中,我们主要剖析c++中的动态内存管理,包括malloc.new expression.operator new.array new和allocator内存分配方法以及对应的内存释放方 ...

  3. c++动态内存管理与智能指针

    目录 一.介绍 二.shared_ptr类 make_shared函数 shared_ptr的拷贝和引用 shared_ptr自动销毁所管理的对象- -shared_ptr还会自动释放相关联对象的内存 ...

  4. (原创)动态内存管理练习 C++ std::vector<int> 模拟实现

    今天看了primer C++的 “动态内存管理类”章节,里面的例子是模拟实现std::vector<std::string>的功能. 照抄之后发现编译不通过,有个库函数调用错误,就参考着自 ...

  5. uCGUI动态内存管理

    动态内存的堆区 /* 堆区共用体定义 */ typedef union { /* 可以以4字节来访问堆区,也可以以1个字节来访问 */ ]; /* required for proper aligne ...

  6. Keil C动态内存管理机制分析及改进(转)

    源:Keil C动态内存管理机制分析及改进 Keil C是常用的嵌入式系统编程工具,它通过init_mempool.mallloe.free等函数,提供了动态存储管理等功能.本文通过对init_mem ...

  7. FreeRTOS 动态内存管理

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...

  8. C++程序设计入门 引用和动态内存管理学习

    引用: 引用就是另一个变量的别名,通过引用所做的读写操作实际上是作用于原变量上. 由于引用是绑定在一个对象上的,所以定义引用的时候必须初始化. 函数参数:引用传递 1.引用可做函数参数,但调用时只需 ...

  9. 动态内存管理详解:malloc/free/new/delete/brk/mmap

    c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, calloc/realloc 上述8个函数/操作符是c/c++语言里常用来做动 ...

随机推荐

  1. python3.5之输出HTML实体字符

    出  关①   徐兰 凭山俯海古边州, 旆②影风翻见戍楼. 马后桃花马前雪,出关争得不回头? [注]关,指居庸关.②旆(pèi),旌旗. 刚刚学习用python写爬虫,实战一下. 抓取出一个网页的内容 ...

  2. C/C++招聘的一些感受和经验【转】

    找工作本人认为最重要的就是前期准备了.     首先.简历一定要写的切合主题.招聘单位要的是你的技能,这个只要大概能符合就可以,关键他们需要的是你的开发经验,一定要在简历中完美的体现出你之前所参与的项 ...

  3. ELMAH+MVC4+SQLite 错误日志

    任何程序我想无论是在调试开发阶段还是上线运营阶段,都能够使人“放心”,不要出什么意外,也不要玩什么心跳:那就需要比较到位和及时的异常与错误日志模块. 本文将简要描述ELMAH.MVC4与SQLite这 ...

  4. java 执行linux命令

    原文地址: http://blog.csdn.net/xh16319/article/details/17302947 package scut.cs.cwh; import java.io.Inpu ...

  5. RobotFramework环境搭建

    环境搭建 1. 准备条件 python-2.7.7 https://www.python.org/download/releases/2.7.7/ wxPython2.8-win32-unicode- ...

  6. Apache开启expires响应头,优化缓存

    apache开始expires响应头输出 expires是什么 指示资源什么时候过期的时间值(GMT时间),在指定的过期时间前,浏览器可以直接使用自身缓存的版本,而不用向服务器发请求,大大减轻服务器压 ...

  7. vs指定QT的工作目录(其它项目也是如此)

    当一个工程依赖第三方动态库时,这时vs编译出来后,运行会提示缺少动态库.解决方法: 项目->属性->调试: 工作目录:指定程序运行时的目录 环境:指定程序运行时的环境变量 我们可以在环境变 ...

  8. WPF的重要新概念

    原文 http://www.cnblogs.com/free722/archive/2011/11/12/2238654.html 逻辑树与可视树 XAML天生就是用来呈现用户界面的,这是由于它具有层 ...

  9. 原来ipad的浏览器也可以直接clip到evernote

    今天才发现是有方法通过邮件方式保存ipad上浏览的内容到evernote,之前以为要反复切换app来做到. 只要在toread.cc登记evernote对应帐号的邮箱,就可以根据toread返回到ev ...

  10. Openstack 的 RPC使用。

    大家都已经很熟悉了RPC了. 比如说nfs就是采用的RPC通信. 尤其SUN RPC 已经成为了C语言开发的经典一种进程间调用机制. openstack 的RPC 机制, 是基于AMQP 活着其他高级 ...