標准C++規定new一個對象時如果分配內存失敗就應拋出一個std::bad_alloc異常,如果不希望拋出異常而僅僅傳回一個NULL指針,可以用new的無異常版本:new(nothrow)。
VC6.0在<new>頭文件中聲明了這兩種Operator new操作符:
void *__cdecl Operator new(size_t) _THROW1(std::bad_alloc);
void *__cdecl Operator new(size_t, const std::nothrow_t&) _THROW0();
並分別定義在newop.cpp和newop2.cpp中。而_THROW0和_THROW1則是兩個宏,在Include目錄的xstddef文件中定義:
#define _THROW0() throw ()
#define _THROW1(x) throw (x)
newop.cpp和newop2.cpp對應的目標模塊被打包進標准C++庫中。標准C++庫有若干個版本: libcp.lib(單線程靜態版)、libcpd.lib(單線程靜態調試版)、libcpmt.lib(多線程靜態版)、libcpmtd.lib(多線程靜態調試版)、msvcprt.lib(多線程動態版的導入庫),msvcprtd.lib(多線程動態調試版的導入庫),這些庫與相應版本的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 <new>
#include <iOStream>
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裡的
[1] [2] 下一頁