WEB开发网
开发学院软件开发VC VC6下使用STL注意:不要让内存分配失败导致您的旧版... 阅读

VC6下使用STL注意:不要让内存分配失败导致您的旧版STL 应用程序崩溃

 2010-07-15 20:45:37 来源:WEB开发网   
核心提示:标准模板库越来越多的开发人员依赖 STL 进行 C++ 开发,STL 提供了丰富的基于 C++ 模板的类和函数,VC6下使用STL注意:不要让内存分配失败导致您的旧版STL 应用程序崩溃(2),在应用程序中使用 STL 有几个好处,首先,如果构建的类有 std::string 成员变量,在构造函数的初始化部分将调用该类

标准模板库

越来越多的开发人员依赖 STL 进行 C++ 开发。STL 提供了丰富的基于 C++ 模板的类和函数。在应用程序中使用 STL 有几个好处。首先,该库为多种通用任务提供了一致的接口。第二个好处是,该代码已经被广泛测试,并有理由认为代码中没有错误。最后,其算法是最佳的。

为了使 STL 工作,宿主编译器必须实现 STL 所写入到的 C++ 标准。Visual C++ 编译器预包装有 STL 实现,还可使用很多其他供应商的实现。

如果您正在使用 Visual C++ 编译器(最高至 6.0 版本),则 STL 将按照期望进行工作,但有一点显著不同 — 内存不足的情况会导致运算符 new 失败。

Visual C++ 6.0 和运算符 New

当运算符 new 失败返回 NULL 时,可以认为这是个错误,因为这与声明在失败时运算符 new 应当引发异常的标准背道而驰。我所了解的所有 STL 实现,包括 Visual C++ 随附的版本,都期望运算符 new 在失败时会引发异常。

虽然改变运算符 new在失败时引发异常的行为是有可能的,我将在后面说明这一点,但这本身将导致进一步的异常。首先,我将说明在默认环境下运算符 new 失败时会发生什么情况。我的所有测试都是利用运行于 Windows NT®4.0 Service Pack 6a 和 Windows®2000 SP2 下的 Visual C++ 6.0, SP4 和 SP5 进行的。据我所知,这种行为将会影响用任何版本的 Visual C++ 编译器(6.0 SP5 版本或更高版本)在所有操作系统上构建的代码。利用 Visual C++ 版本 7.0 和 7.1 已经测试了同样的代码,这两种版本都显示了运算符 new 失败时符合标准的行为。使用的 STL 库是 Visual C++ 和 STLPort (http://www.stlport.org) 实现随附的版本。

为了解释 STL,我将使用最常用的 STL 类 std::string,尽管描述的行为适用于任何为运算符 new 分配堆内存的 STL 函数或类。在该示例中,我们假定试图用一些数据构造一个新的字符串对象,并且堆分配将会失败。下列代码片断将可以满足要求:

#include <string>
void Foo()
{
std::string str("A very big string");
}

图 2 中的代码摘自 Visual C++ 6.0 随附的 STL 字符串类代码。构造函数最终引起 std::basic_string<>::_Copy。 图 2 中显示的是其中的一部分,删除了部分代码。在 try 块中,局部变量 _S 被赋给 allocator.allocate 的返回值,反过来,它调用运算符 new。对于默认的 Visual C++ 6.0 行为,在失败时运算符 new 将返回 NULL 值,这导致 NULL 值被赋给局部变量 _S。关键是没有引发异常。

要执行的下一行代码是将 _S + 1 赋值给成员变量 _Ptr。因为 _S 的值为 NULL,值 0x00000001 将被赋给变量 _Ptr。接下来的一行,_Refcnt( Ptr) = 0,有效地返回 _Ptr - 1(实际为 _Ptr[-1]),它根据由运算符 new 返回的原始 NULL 指针值进行求值。_Refcnt 成员函数返回对 NULL 指针第一个元素的引用,而随后将 0 赋给该引用(本质是 *NULL= 0),由于即时访问冲突该引用将失败。除了安装结构化异常处理程序来捕捉该错误这样极其苛刻的措施外,并没有办法制止由于访问冲突而终止应用程序。虽然这种行为好像是由错误引起的,STL 代码实际上也是正确的,但为了得到正确的行为,它要求运算符 new 在失败时引发异常。

现在让我们看一下在运算符 new 失败引发异常时的执行流程。如前面所示,将执行对 allocator.allocate 的初始调用。当运算符 new 失败时,引发 std::bad alloc 异常,代码引起 catch(...) ( CATCH ALL) 处理程序,该处理程序重新尝试分配,请求的内存可能会较小。如果第二次分配失败,将进一步引发 std::bad alloc 异常,这将传播回代码,使 std::string 对象为已定义的空状态。

应注意该重载的字符串构造函数可能会引发异常。如果构建的类有 std::string 成员变量,在构造函数的初始化部分将调用该类的重载构造函数,应仔细阅读 Robert Schmidt 的“Handling Exceptions, Part 10”的 Deep C++ 专栏。

Tags:VC 使用 STL

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接