Click to See Complete Forum and Search --> : STL Exceptions
JasonD
April 15th, 2004, 02:17 PM
It is surprisingly hard to find information regarding STL exceptions on the 'net. I know the STL implementation with MSVC++ .NET throws an exception of type bad_alloc (derived from runtime_error, derived from exception) when there is an out-of-memory error. However, I have tried this in a second thread of a multithreaded program, and the program will not catch the out-of-memory exception with any of the standard exception classes defined. Of course, the catch-all catches it, but I would like to know its type. I can find no information on why this behaviour changes in multithreaded programs.
Can anyone explain this behaviour? Thanks for any help.
Andreas Masur
April 16th, 2004, 05:47 AM
Well...what compiler did you use? Microsoft compilers do not throw a 'bad_alloc' exception but rather return a NULL pointer...
JasonD
April 16th, 2004, 09:08 AM
Thanks for the reply, Andreas Masur.
Sorry, I should have been more explicit. I am using the MSVC++ .NET 2003 compiler (version 7.1). I will further explain:
I knew this board was a sub-category of Visual C++ / C++ Programming, so when I posted I assumed everyone knew I was using some version of the MSVC++ compiler. However, I forgot about the differences between versions 6.0 and lower and 7.0 and above. You are partially correct in that MSVC++ 6.0 and below did not throw an exception, but instead, incorrectly returns NULL. However this has been fixed since version 7.0. It now correctly throws an exception. Here is a good article that explains this, from MSDN Magazine:
VISUAL C++ 6.0 - Don't Let Memory Allocation Failures Crash Your Legacy STL Application (http://msdn.microsoft.com/msdnmag/issues/03/09/LegacySTLFix/default.aspx)
In any case, I have certainly verified that MSVC++ 7.1 does throw a bad_alloc. I have even looked through the source code for the STL classes to find that it does, eventually, use the new operator, and I have verified that the new operator throws a bad_alloc. But it only does so in my single-threaded program. In my multi-threaded program, when the error occurs in one of the threads, it throws something - I just have no idea what type it is. I wonder if there is a way to extract this from the debugger (I must admit that I have never attempted to debug a multi-threaded application before, nor have I attempted to debug exceptions). Note that both of these tests are within the same program, therefore I am using the multi-threaded runtime library for both, so the runtime library is not the cause.
Andreas Masur
April 16th, 2004, 09:43 AM
Originally posted by JasonD
I knew this board was a sub-category of Visual C++ / C++ Programming, so when I posted I assumed everyone knew I was using some version of the MSVC++ compiler.
Well...this is halfway correct...this forum will discuss any multithreaded question...disregarding of the platform or compiler.
Originally posted by JasonD
However, I forgot about the differences between versions 6.0 and lower and 7.0 and above. You are partially correct in that MSVC++ 6.0 and below did not throw an exception, but instead, incorrectly returns NULL. However this has been fixed since version 7.0. It now correctly throws an exception. Here is a good article that explains this, from MSDN Magazine:
VISUAL C++ 6.0 - Don't Let Memory Allocation Failures Crash Your Legacy STL Application (http://msdn.microsoft.com/msdnmag/issues/03/09/LegacySTLFix/default.aspx)
I admit that I did not read that article yet, however, I would be really surprised if .NET 2003 would throw the exception now. Not throwing the 'bad_alloc' exception was considered being a bug and was expected to be fixed by the time, .NET would be released. At the time, .NET 2002 actually came out and Microsoft changed its mind, leaving the bug as it was...that is, returning a NULL pointer instead. There was a knowledge base article about their decision as far as I remember. I do not have it handy at the moment, but I will get back with it later. I did not read anything about .NET 2003 yet, and I did not test it...however, as I said, I would be rather surprised if they fixed this bug with this version (and if so, I would definitely like to know their reasons... :cool: )
Originally posted by JasonD
In any case, I have certainly verified that MSVC++ 7.1 does throw a bad_alloc. I have even looked through the source code for the STL classes to find that it does, eventually, use the new operator, and I have verified that the new operator throws a bad_alloc. But it only does so in my single-threaded program. In my multi-threaded program, when the error occurs in one of the threads, it throws something - I just have no idea what type it is. I wonder if there is a way to extract this from the debugger (I must admit that I have never attempted to debug a multi-threaded application before, nor have I attempted to debug exceptions). Note that both of these tests are within the same program, therefore I am using the multi-threaded runtime library for both, so the runtime library is not the cause.
As being mentioned...I would be surprised, nevertheless, if so, then there should not be any difference...do you do a try within your thread function itself?
JasonD
April 16th, 2004, 10:19 AM
Originally posted by Andreas Masur
Well...this is halfway correct...this forum will discuss any multithreaded question...disregarding of the platform or compiler. Understood.
Originally posted by Andreas Masur
I admit that I did not read that article yet, however, I would be really surprised if .NET 2003 would throw the exception now. Not throwing the 'bad_alloc' exception was considered being a bug and was expected to be fixed by the time, .NET would be released. At the time, .NET 2002 actually came out and Microsoft changed its mind, leaving the bug as it was...that is, returning a NULL pointer instead. There was a knowledge base article about their decision as far as I remember. I do not have it handy at the moment, but I will get back with it later. I did not read anything about .NET 2003 yet, and I did not test it...however, as I said, I would be rather surprised if they fixed this bug with this version (and if so, I would definitely like to know their reasons... :cool: ) I have never tested my program on MSVC++ .NET 2002 (v7.0), but on MSVC++ .NET 2003 (v7.1) it definitely throws an exception. I would be happy to show you the output of any test program you would like to run on my compiler.
If you could find that knowledge base article, I would be interested in reading it, as well. It wouldn't be this one, would it?
167733 - PRB: Operator New Doesn't Throw bad_alloc Exception on Failure (http://support.microsoft.com/?kbid=167733)
I just did a search for it, and I realized that is it actually linked from the article I posted:
Don't Let Memory Allocation Failures Crash Your Legacy STL Application (http://msdn.microsoft.com/msdnmag/issues/03/09/LegacySTLFix/default.aspx)
Although, their comments on the knowledge base article state: "do not implement the solution given there. I will explain why you shouldn't later in this article"
This KB article claims that it applies to Microsoft Visual C++ .NET (2002) and Microsoft Visual C++ .NET (2003), but the article I linked to states, "The default behavior has changed for Visual C++ .NET, both for version 7.0 (Visual C++ .NET 2002) and 7.1 (Visual C++ .NET 2003), which throws an exception when operator new fails. ... If you are developing with Visual C++ .NET, you will find that the issues raised here have been fixed" which I have confirmed. I do not need to fix the new operator if it is throwing bad_alloc exceptions already.
Originally posted by Andreas Masur
As being mentioned...I would be surprised, nevertheless, if so, then there should not be any difference...do you do a try within your thread function itself? Yes, I have a try...catch block in the main function, in the thread function, and in the function the thread calls to make the allocation. I am using the STL list class, attempting to add an item to a doubly-linked list. The purpose of my program is to vigorously test multiple threads changing the same list, and to trap out-of-memory conditions.
JasonD
April 16th, 2004, 01:02 PM
Update: I have confirmed that the new operator within a new thread of a multi-threaded application throws a bad_alloc exception when the memory allocation fails.
Apparently something fishy is going on when the memory allocation failure is caused by the STL's list class's attempt to add another element to the list. It is supposed to merely use the new operator, and I have verified that it does. So, why does it show different behaviour?
Andreas Masur
April 16th, 2004, 02:41 PM
Okay...now we have some clarification here...there are actually two implementations of the global operator 'new' - one in the CRT ('libc.lib' or 'msvcrt.lib'/'msvcr70.dll'), one in the STL library ('libcp.lib' or 'msvcprt.lib'/'msvcp70.dll'). The former one will still return NULL (for backward compatibility, the latter one will actually throw in compliance with the standard.
Thus, if you want to use the 'throwing' one, you need to make sure that the appropriate library gets linked to your application. This can usually be reached by including the header '<new>'. However, this still can lead to using the wrong 'new' operator since you manually can change the order of the libraries within the project settings.
In other words, you are correct, there is a operator 'new' in .NET which actually conforms to the standard by throwing a 'bad_alloc' exception.
Nevertheless, even with knowing that, I can't give you a direct answer why this one would behave differently....one thing that of course comes to my mind...maybe check the order of the libraries and check that you link against the correct one...if you do not see anything wrong there, consider creating a .map file and check where the operator 'new' comes from (the decorated name should be '??2@YAPAXI@Z' if I remember correctly)...
JasonD
April 18th, 2004, 07:58 PM
Andreas Masur, thanks again for your detailed reply.
I should note that, in every case I have tried, STL always throws an exception within MSVC++ 7.1. My only problem is what type of exception is thrown. It should be bad_alloc when it is an out of memory error.
I checked the directory order for my MSVC++ 7.1 compiler, and the first library listed is:
$(VCInstallDir)lib
which is:
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\lib
which contains both the libc.lib and the libcp.lib libraries that you speak about. So, it appears that the directory order does not matter in this case as they are both in the same directory (i.e. one cannot be listed before the other). I should note that this is the default settings for MSVC++ 7.1, as I have not changed the order, nor added other directories. In any case, I would assume that the STL functions would use the STL library (libcp.lib), which you have stated throws an exception in compliance with the standard.
I do not know how to create a .map file to check where the operator 'new' comes from. One thing I find annoying about the editor is when I request to find the declaration of a variable/function it sometimes has absolutely no clue where it is defined. It will either ask me to select one from a list, or go to the wrong declaration, or even state that the variable is not defined (immediately following a successful compile, which indicates otherwise).
-----------
I have found something interesting from additional tests:
One of the problems I have with testing out of memory errors is that I have to run the system out of memory (I wish there was a way developers could test applications in a restricted state that emulates a low memory system). Surprisingly, nothing crashes in the process, even with the editor running in the background. One method around this is to ask for an allocation of memory that is far greater than what it exists even with virtual memory, such as 2 gigabytes. This fails immediately without the computer running out of memory. I decided to replace my doubly linked list 'add item' function with a declaration of an STL vector that is 2 GB in size. It fails immediately with a bad_alloc. This seems to state that I am indeed linking to the proper 'new' operator (I assumed this was the case all along, because a bad_alloc was thrown in my single threaded STL testing app). The problem is that I cannot do such a test with an STL list, as the value being added to the list must exist (I cannot have a 2 GB variable within the program to add to the list). All I can do is change the size of the item. Changing the size of the item actually matters. If the list is of a structure that is 16 kb in size, then 'add item' function fails with a bad_alloc exception. If it is just 40 bytes in size, it fails with an unknown exception type. This does so in debug and release mode.
I guess I am going to have to handle the bad_alloc as I would normally, but also ensure that I have a catch-all to handle any other possible exception types.
codeguru.com
Copyright WebMediaBrands Inc., All Rights Reserved.