如果新的失败,是否需要检查指针有效性?

时间:2012-06-18 19:49:00

标签: c++ pointers

正如标题所说,我知道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;
}

4 个答案:

答案 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时)