3

new 演算子がメモリの割り当てに失敗した場合、 new ステートメントをすぐに囲む try-catch ブロックを配置した場合にのみ、例外 std::bad_alloc がキャッチされます。代わりに、数スタックフレーム下の呼び出し元に try-catch ブロックがある場合、そこでキャッチされず、異常なプログラム終了が発生します。なぜこれが起こるのですか?これは Microsoft Visual Studio 2008 上にあります。

編集:OK、これは機能していないコードです。すぐ下の関数は new を呼び出している場所で、その下の関数はその下のスタックフレームです。最後の関数は、catch 句がある場所ですが、そこでキャッチされません。

void HTTPResponseBuff::grow()
{
    if (m_nMaxSize > m_nStartConstGrowSize)
        m_nMaxSize += m_nConstGrowSize;
    else
        m_nMaxSize = 2 * m_nMaxSize;

    char* pTmp = new char[m_nMaxSize];
    . . . 
}

void HTTPResponseBuff::write(const char* pBuf, size_t len)
{
    char* pCh;
    while (getRemainingCapacity(pCh) < len)
        grow();
    . . . 
}

size_t HTTPTransport::responseCallback(void *pRespData, size_t size,
                             size_t nmemb, void *pRespBuff)
{
    const char* pChar = (const char*)pRespData;
    register int respDataLen = size * nmemb;    
    ((HTTPResponseBuff*)pRespBuff)->write(pChar, respDataLen);
    return respDataLen;
}

A few curl library stackframes here. These are C code, not C++.

ISTATUS HTTPTransport::invoke()
{
    invokeCleanup();

    //make the HTTP call
    CURLcode retCode;
    try{
    retCode = curl_easy_perform(m_pCurl);
    }
    catch(std::bad_alloc& ba)
    {
        strcpy(m_pErrMsg,ba.what());
        m_status = IFAILURE;
    }
}

また、bad_alloc をキャッチしたときのスタックフレーム (新しいステートメントをすぐに囲む catch 句内) は次のとおりです

4

2 に答える 2

2

例外の発生元と try-catch の間にあるサードパーティの機能について言及しました。これらのサードパーティ関数が c++ でない場合 (たとえば、libcurl が c で記述されているように、c リンケージがある場合)、例外処理は期待どおりに機能しません。gcc を使用するプロジェクトでも同じ問題が発生しました。

コールバックですべての例外をキャッチしてから、それらがサード パーティ レイヤーを介して伝播し、エラー コード (またはカスタム メカニズム) を使用して情報を呼び出し元に取得するか、例外の使用を完全にあきらめる必要があります。


あなたが私が何をしたかを尋ねるように: 私は利用可能な void ポインターを介してコールバックに注入された呼び出し元からのコンテキスト オブジェクトを持っていました。そこで、コンテキスト オブジェクトを変更して ErrorStatus メンバーと ErrorMessage メンバーを持ち、これらを使用して C 層を通じてエラーを伝播しました。

struct Context{
    ErrorCode errorCode;
    const char* errorMessage;
    //other stuff
}

void callback(T arg, void* context){
   try{
      new(int);
   }catch(std::exception &e){
       context.errorCode=getErrorCode(e);
       context.errorMessage=e.what();
   }

}

void caller(){
    Context context;
    thirdparty_function(context);

}

スレッドの安全性について心配していない場合は、そのためにグローバル変数を使用することもできます。

とはいえ、この方法でメモリ不足エラーを処理するのは難しい場合があります。エラー メッセージ用に追加のメモリを割り当てないようにする必要があるからです。

于 2011-07-27T10:06:33.217 に答える
0

可能であればコードを投稿してください。コードなしで簡単なテストを作成しましたが、try/catch はスタックフレームが少し離れていても正常に動作しているようです (この例は gcc で正常に動作します)。

void foo()
{
    int* myarray= new int[1000000000];
}

void foo1()
{
     int i = 9;
     foo();
}

void foo2()
{
     int j = 9;
     foo1();
}

int main () {
  try
  {
         foo2();
  }
  catch (exception& e)
  {
    cout << "Standard exception: " << e.what() << endl;
  }
  system("pause");
  return 0;
}

出力は

標準例外: St9bad_alloc

于 2011-07-27T10:00:25.347 に答える