std :: bad_alloc не попадает ни в один вызывающий стек - PullRequest
3 голосов
/ 27 июля 2011

Если новый оператор не может выделить память, исключение std :: bad_alloc перехватывается только тогда, когда я помещаю блок try-catch, непосредственно окружающий новый оператор. Если вместо этого у меня есть блок try-catch в вызывающей программе, расположенной несколькими кадрами стека внизу, он не попадет туда, и я получаю ненормальное завершение программы. Почему это происходит? Это на Microsoft Visual Studio 2008.

Редактировать: Хорошо, вот код, который не работает. Непосредственно ниже функция - это то место, где я вызываю новый, а нижеприведенные - это кадры стека под ним. В последней функции у меня есть предложение 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, непосредственно окружающем новый оператор): http://s289.photobucket.com/albums/ll211/spiderman2_photo_bucket/?action=view&current=bad_alloc.jpg

Ответы [ 2 ]

2 голосов
/ 27 июля 2011

Вы упомянули сторонние функции между источником исключения и try-catch.Если эти сторонние функции не являются c ++ (например, имеют связь c, как libcurl, пишущий на 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);

}

Если вы не беспокоитесь о безопасности потоков, вы также можете использовать глобальные переменные для этого.

Тем не менее, обработка ошибок нехватки памяти таким способом может быть сложной, потому что вам следует избегать выделения дополнительной памяти для сообщений об ошибках

0 голосов
/ 27 июля 2011

Опубликуйте ваш код, если это возможно, без вашего кода я написал небольшое тестирование, и 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

...