1

As title says, i know that new throws an exception which can be caught, but what exactly happens to the pointer? it turns NULL? I checked some answers on SO but none explained it. Check example below, the pointer keeps on the heap? please give full info on this pattern

#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

4 に答える 4

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ため、存在しなくなります。1つのレベルを移動する:

  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ポインターの場合、操作は効果がありません。

何もすることがないので、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これを行うときは、ここで行ったように、nullポインターに初期化することが特に重要であることに注意してください。そうでない場合:

CFileStatic* pFile; // NO INIT
/* ... */
delete pFile; // if new threw, this is undefined behavior

pFileまだガベージポインタになります。これはnullポインターではないため、delete削除しようとします。その結果、未定義動作が発生します。

于 2012-06-18T19:52:07.183 に答える
3

関数から例外がスローされると、関数は完了せず、何も返されません。同時に、制御フローは例外ハンドラーにジャンプし、関数が返された場合でも、受信ポインターへの割り当ては実行されません。

のスローバージョンについても同じnewことが言えます。スローする場合、ポインタは式の前と同じ値を維持します。これはNULLまたはその他の値である可能性があります。

一方、を使用するnew (std::nothrow) X;と、toの呼び出しnewはスローされず、失敗はNULL値が返される(およびポインターに割り当てられると想定される)ことで示されます。

于 2012-06-18T19:53:47.270 に答える
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.

お役に立てれば!

于 2012-06-18T19:53:12.363 に答える
1

バージョンを使用しない限り、失敗した場合は例外newがスローされます。これは、返されたポインタを格納する変数の値が変更されないことを意味します。std::bad_allocnothrow

例外をキャッチすると、の値はpFile初期化されないままになります。それ以外の場合、アプリケーションmainは終了します (終了したまま) 。

于 2012-06-18T19:51:27.163 に答える