| |
| |
VC6.0如何让new失败后抛出异常 |
来源:Internet 点击数: 更新时间:2006-5-17 23:09:38  |
C标准库一起使用,比如libcp.lib与libc.lib搭配。另外,VC6.0在new.cpp还定义了一个operator new,原型如下 :
void * operator new( unsigned int cb )
而new.cpp对应的目标模块却是被打包进C标准库中的(是不是有点奇怪?)。
一般来说,程序员不会显式指定链接C++标准库,可是当程序中确实使用了标准C++库时链接器却能聪明地把相应的C++标准库文件加进输入文件列表,这是为什么?其实任何一个C++标准头文件都会直接或间接地包含use_ansi.h文件,打开它一看便什么都清楚了(源码之前,了无秘密) :
/*** *use_ansi.h - pragmas for ANSI Standard C++ libraries * * Copyright (c) 1996-1997, Microsoft Corporation. All rights reserved. * *Purpose: * This header is intended to force the use of the appropriate ANSI * Standard C++ libraries whenever it is included. * * [Public] * ****/
#if _MSC_VER > 1000 #pragma once #endif
#ifndef _USE_ANSI_CPP #define _USE_ANSI_CPP
#ifdef _MT #ifdef _DLL #ifdef _DEBUG #pragma comment(lib,"msvcprtd") #else // _DEBUG #pragma comment(lib,"msvcprt") #endif // _DEBUG
#else // _DLL #ifdef _DEBUG #pragma comment(lib,"libcpmtd") #else // _DEBUG #pragma comment(lib,"libcpmt") #endif // _DEBUG #endif // _DLL
#else // _MT #ifdef _DEBUG #pragma comment(lib,"libcpd") #else // _DEBUG #pragma comment(lib,"libcp") #endif // _DEBUG #endif
#endif // _USE_ANSI_CPP
现在我们用实际代码来测试一下new会不会抛出异常,建一个test.cpp源文件:
// test.cpp #include #include
using namespace std;
class BigClass { public: BigClass() {} ~BigClass(){} char BigArray[0x7FFFFFFF]; };
int main() { try { BigClass *p = new BigClass; } catch( bad_alloc &a) { cout << "new BigClass, threw a bad_alloc exception" << endl; }
BigClass *q = new(nothrow) BigClass; if ( q == NULL ) cout << "new(nothrow) BigClass, returned a NULL pointer" << endl; try { BigClass *r = new BigClass[1]; } catch( bad_alloc &a) { cout << "new BigClass[1], threw a bad_alloc exception" << endl; } return 0; }
根据VC6.0编译器与链接器的做法(请参考《为什么会出现LNK2005"符号已定义"的链接错误?》),链接器会首先在C++标准库中解析符号,然后才是C标准库,所以如果开发者没有自定义operator new的话最后程序链接的应该是C++标准库中newop.obj和newop2.obj模块里的代码。可是程序运行的结果却是:
new(nothrow) BigClass, returned a NULL pointer
显然程序始终未抛出bad_alloc异常。单步跟踪观察,发现第1个和第3个new实际上调用了new.cpp里的operator new,而第二个new(nothrow)则正确地调用了newop2.cpp定义的版本。很难理解是吧?但是当你用
dumpbin /SYMBOLS libcp.lib
dump出libcp.lib所有的符号信息时,你会发现其中的newop.obj模块没有定义任何符号(其它版本也一样)。不可思议!newop.cpp的实现代码明明写在那儿,怎么会....?让我们再仔细看看newop.cpp,咦,operator new的定义被包裹在一个#if...#endif块中:
#if !defined(_MSC_EXTENSIONS)
... ...
void *__cdecl operator new(size_t size) _THROW1(_STD bad_alloc) { ... ... }
#endif
原来需要_MSC_EXTENSIONS宏未定义,实现代码才是有效的啊。那么这个宏是什么意思?其实Visual C++在语言层面上对ANSI C标准做了一些特殊的扩展,定义_MSC_EXTENSIONS意味着编译器支持这样的扩展,没有定义它编译器就会严格按照ANSI C标准来编译程序。实际上如果指定了编译选项/Ze编译器就会自动定义这个宏,指定/Za则不会,而且/Ze是缺省选项。作者猜想Visual Studio的开发人员在build标准C++库时很可能没有指定/Za,导致newop.cpp中的operator new定义被无情抛弃。是他们的疏漏吗?我看未必,大家可以试试用/Za选项去编译那些标准库文件,看看有多少编译不通过。VC标准库的实现用了很多微软扩展的语言特性,不指定/Za是情有可原的,我不明白的是newop.cpp的作者(好象是P.J. Plauger老人家)为什么会加上一个如此愚蠢的"#if !defined(_MSC_EXT[1] [2] 下一页
| |
| |
|