VC6.0如何让new失败后抛出异常

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_EXTENSIONS)",因为实在看不出这个operator new定义与_MSC_EXTENSIONS有什么冲突的地方。   既然标准C++库里的newop.obj是个空壳,那我们就只好自己动手丰衣足食了。把newop.cpp和dbgint.h(都在VC98/crt/src目录下)拷贝到test.cpp所在的目录,并将newop.cpp中的 #include   改成 #include "dbgint.h"   然后用 cl /c /Za /D_CRTBLD newop.cpp   编译它。/D_CRTBLD定义了_CRTBLD宏,为什么这么做呢?因为dbgint.h属于内部头文件,VC不希望应用程序用到它,便在文件中埋伏了这么一段: #ifndef _CRTBLD /* * This is an internal C runtime header file. It is used when building * the C runtimes only. It is not to be used as a public header file. */ #error ERROR: Use of C runtime library internal header file. #endif /* _CRTBLD */   可我们确确实实是想build标准库(的一部分),所以只好强行突破这个限制了。然后编译test.cpp: cl /c /GX test.cpp   最后进行链接: link test.obj newop.obj   这时再运行test.exe输出的结果就是 new BigClass, threw a bad_alloc exception new(nothrow) BigClass, returned a NULL pointer new BigClass[1], threw a bad_alloc exception   值得庆幸的是虽然VC6.0如此弱智,但VC7.1却表现良好,原因是VC7.1的newop.cpp和newaop.cpp(数组版)取消了那个愚的"#if !defined(_MSC_EXTENSIONS)",于是标准C++库中的newop.obj和newaop.obj模块都实实在在地有了相应代码。另外,nothrow版的定义也分别转移到了newopnt.cpp和newaopnt.cpp中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值