3

如果 new 运算符未能分配内存,则只有当我在 new 语句周围放置一个 try-catch 块时,才会捕获异常 std::bad_alloc 。如果我在下面几个堆栈帧的调用者中有 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¤t=bad_alloc.jpg

4

2 回答 2

2

您提到了异常来源和 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);

}

如果你不担心线程安全,你也可以使用全局变量。

也就是说,以这种方式处理内存不足错误可能会很棘手,因为您应该避免为错误消息分配额外的内存

于 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 回答