正如标题所说,我知道new会抛出一个可以捕获的异常,但指针究竟发生了什么?它变成了NULL?我在SO上检查了一些答案,但没有人解释。 检查下面的例子,指针保持在堆上?请提供有关此模式的完整信息
#include <windows.h>
#include <cstdlib>
#include <iostream>
using namespace std;
enum eReadMode
{
// READ_ONLY,
READ_WRITE,
// CREATE_FILE,
// CREATE_WRITE_FILE,
};
class CFileStatic
{
private:
FILE *m_File;
public:
CFileStatic( LPCTSTR szFileName, eReadMode eMode );
virtual ~CFileStatic() {};
bool IsValidFile() const { return( m_File != NULL ); };
void PrintFile( unsigned int uLine = 0 );
};
CFileStatic::CFileStatic( LPCTSTR szFileName, eReadMode eMode )
{
if( szFileName )
{
if( eMode == READ_WRITE )
m_File = fopen( szFileName, "r+" );
else
printf( "Valid usage of: READ_WRITE only" );
}
else
m_File = NULL;
}
void CFileStatic::PrintFile( unsigned int uLine )
{
static unsigned uFindNumber;
if( uLine == 0 )
{
char szBuffer[1024];
while( fgets( szBuffer, 1024, m_File ) )
{
std::cout << szBuffer;
}
}
else
{
char szBuffer[1024];
while( fgets( szBuffer, 1024, m_File ) )
{
uFindNumber++;
if( uFindNumber == uLine )
{
std::cout << szBuffer;
}
}
}
}
int main( int argc, char *argv[] )
{
//if new fails, what 'pFile' turns out to be? and do I need to delete
//it later?
CFileStatic *pFile = new CFileStatic( "Console.h", READ_WRITE );
if( pFile->IsValidFile() )
{
pFile->PrintFile(2);
}
CFileStatic *pConsoleCpp = new CFileStatic( "Console.cpp", READ_WRITE );
if( pConsoleCpp->IsValidFile() )
{
pConsoleCpp->PrintFile();
}
system("pause>nul");
return EXIT_SUCCESS;
}
答案 0 :(得分:6)
假设您使用的是默认的全局new
运算符,并且未使用nothrow
版本的new
:
int main( int argc, char *argv[] )
{
//if new fails, what 'pFile' turns out to be? and do I need to delete
//it later?
CFileStatic *pFile = new CFileStatic( "Console.h", READ_WRITE );
/* ... */
}
没有“以后”。在此代码中,如果new
失败,则会抛出std::bad_alloc
异常,您的程序将立即终止。
现在,如果您尝试处理这种情况,则需要捕获该异常。也许是这样的:
int main( int argc, char *argv[] )
{
//if new fails, what 'pFile' turns out to be? and do I need to delete
//it later?
try
{
CFileStatic *pFile = new CFileStatic( "Console.h", READ_WRITE );
}
catch( const std::bad_alloc& ex )
{
cout << "whoops! out of memory." << ex.what() << endl;
}
/* ... */
}
pFile
存在于try
块所包含的范围内,因此不再存在。搬出一个级别:
CFileStatic * pFile = 0;
try
{
pFile = new CFileStatic( "Console.h", READ_WRITE );
}
catch( const std::bad_alloc& ex )
{
cout << "whoops! out of memory." << ex.what() << endl;
}
// pFile is still 0
pFile
永远不会被修改,因此值不变。
关于delete
指针的问题。标准说(C ++ 03 5.3.5 / 2):
[...]如果delete的操作数的值是空指针那么 操作没有效果。
您不必删除NULL指针,因为delete
没有任何内容,但这样做无效。你可以安全地做到这一点:
CFileStatic * pFile = 0;
try
{
pFile = new CFileStatic( "Console.h", READ_WRITE );
}
catch( const std::bad_alloc& ex )
{
cout << "whoops! out of memory." << ex.what() << endl;
}
delete pFile; // regardless of the success of new, this is OK
请注意,执行此操作时,将pFile
初始化为空指针尤其重要,就像我在此处所做的那样。如果你不这样做:
CFileStatic* pFile; // NO INIT
/* ... */
delete pFile; // if new threw, this is undefined behavior
pFile
仍然是垃圾指针。它不是空指针,因此delete
会尝试删除它,导致未定义的行为。
答案 1 :(得分:3)
当一个异常被抛出函数时,函数没有完成并且没有返回任何东西,同时控制流跳转到异常处理程序,即使函数返回,对接收指针的赋值也不会是执行。
同样适用于new
的抛出版本,如果抛出,则指针将保持与表达式之前相同的值,该值可能为NULL或任何其他值。
另一方面,如果你使用new (std::nothrow) X;
,那么对new
的调用将不会抛出,并且将返回一个NULL值(并假设分配给指针)来表示失败
答案 2 :(得分:2)
如果抛出异常,则不会为指针分配新值。如果指针的作用域位于您进行分配的try
块内,或者不在任何try
块中作用域,则该异常将导致作用域更改,使您无法访问指针了。因此,无需测试指针。
另一方面,如果指针在分配失败后以其持续的方式声明,那么您需要检查该值。例如:
T* ptr = NULL;
try {
ptr = new T();
} catch (std::bad_alloc& ) {
/* ... handle error */
}
// Have to test ptr here, since it could still be NULL.
希望这有帮助!
答案 3 :(得分:1)
如果new
失败,则会引发std::bad_alloc
异常,除非您使用nothrow
版本。这意味着存储返回指针的变量值将保持不变。
如果您发现异常,则pFile
的值仍然未初始化,否则您的应用程序将终止(退出main
时)