If the new operator fails to allocate memory, the exception std::bad_alloc is only getting caught if I put a try-catch block immediately surrounding the new statement. If I instead have the try-catch block in a caller a few stackframes down below, it is not getting caught there and I'm getting an abnormal program termaination. Why does this happen? This is on Microsoft Visual Studio 2008.
Edit: Ok, here is the code that is not working. The function immediately below is where I'm c开发者_JAVA百科alling the new, and the ones below are the stackframes below it. The last function is where I have the catch clause but it doesn't get caught there.
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;
}
}
Also the stackframes at the time I caught the bad_alloc (in the catch clause immediately surrounding the new statement) is here: http://s289.photobucket.com/albums/ll211/spiderman2_photo_bucket/?action=view¤t=bad_alloc.jpg
You mentioned third party functions inbetween the exception origin and the try-catch. If these thirdparty functions are not c++(for example have c linkage, like libcurl being written in c) then the exception handling will not work as expected. I had the same issue with a project using gcc.
You need to catch all exceptions in your callbacks before they propagate through the third party layer and use error codes( or a custom mechanism) to get the information into your caller or give up on using the exceptions entirely.
As you ask what I did: I had a context object from the caller injected into the callback through a void pointer available. So I changed the context object to have ErrorStatus and ErrorMessage members and used these to propagate errors through the C-Layer.
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);
}
If you are not worried about thread safety you also could use global variables for that.
That said, handling out of memory errors this way could be tricky, because you should avoid allocating additional memory for error messages
Post your code if possible, without your code I have wrote a small testing and the try/catch seems to be working fine even with a few more stackframe away(the example works fine with 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;
}
The output is
Standard exception: St9bad_alloc
精彩评论