CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jan 2006
    Location
    Houston
    Posts
    29

    Catching bad_alloc Exceptions

    Hello.

    After having used Visual C++ version 6 for a number of years, and checking for new returning NULL, I am now starting to code with try-catch blocks.

    (I know about the STL and <vector> class, but I’d like to master the try-catch approach too, so please bear with me).

    I am wondering: what exactly is thrown with a bad_alloc exception? Is it a memory address? An integer? . . .

    The reason I ask is because I am trying to write a small program that dynamically creates several arrays. All the examples I have found so far show it to handle an exception when allocating a single array. However, I am finding it tricky to code for multiple arrays. Here’s a code snippet for the try block (say, two 2D arrays, and one hundred 1D arrays):

    Code:
    try { // Beginning of try block
    	b1 = new double[mDim];
    	A = new double*[mDim]; //Allocate space for pointers to rows of A matrix
    	for (i = 0; i < mDim; i++) {
    		A[i] = new double[mDim]; //Allocate space for columns of A matrix
    	}//End for i
    	b2 = new double[mDim];
    	b3 = new double[mDim];
    	b4 = new double[mDim];
    	D = new double*[mDim]; //Allocate space for pointers to rows of D matrix
    	for (i = 0; i < mDim; i++) {
    		D[i] = new double[mDim]; //Allocate space for columns of D matrix
    	}//End for i
    	b5 = new double[mDim];
    	. . .
     
    	b100 = new double[mDim];
    } // End of try block
    How do I code the catch block? If a bad_alloc exception is thrown, I would have to deallocate all arrays created up to that point, wouldn’t I? Something similar to the following might have to be done (assumes all pointers initialized to NULL when first defined):


    Code:
    catch (bad_alloc& xa) { // Catch block, for allocation exceptions
    	cerr << "In catch block, so an allocation failed.\n”;
    	if (b1) delete[] b1;
    	if (A)
    	{//count down from the highest value of i that we reached before the exception
    		 for (; i > 0; --i)		 {
    			 delete[] A[i];
    		 }
    	 delete[] A;
    	}
    	if (b2) delete[] b2;
    	if (b3) delete[] b3;
    	if (b4) delete[] b4;
    	if (D)
    	{//count down from the highest value of i that we reached before the exception
    		 for (; i > 0; --i)		 {
    			 delete[] D[i];
    		 }
    	 delete[] A;
    	}
    	if (b5) delete[] b5;
    	. . .
    	if (b100) delete[] b100;
    	return 0;
    } // End of catch block
    This approach would get very tedious, especially if many more arrays are involved. If bad_alloc was an integer, and the deallocation sequence was ordered properly, the try block could use a switch statement to indicate which array caused the exception to be thrown, and then drop through the rest of the switch statements. Can this be done?

    Your help is much appreciated.


    David

  2. #2
    Join Date
    Apr 2005
    Location
    Norway
    Posts
    3,934

    Re: Catching bad_alloc Exceptions

    Quote Originally Posted by DavidB
    (assumes all pointers initialized to NULL when first defined):
    You can delete NULL-pointers, so if all your pointers are initialized to NULL when defined you don't need all those:
    Code:
    if(ptr) 
        delete ptr;
    This is enough:
    Code:
    delete ptr;
    Anyway, I assume that you have a some destructor/finalizing method that clean up your pointers. What if you call this function from within the catch? That would maybe save you from a lot of work.

    - petter

  3. #3
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: Catching bad_alloc Exceptions

    A bad_alloc gives you no information. Not even the number of bytes you tried to allocate.

    If a bad_alloc failure happened on a small allocation then you have a major memory problem and your best bet is to terminate as cleanly as possible. If it's a critical application / server then you should probably have some already-allocated backup memory that you can use to launch a duplicate server and log any errors etc while yours restarts.

    There are occasions where you might get a bad_alloc because of an attempt to allocate a very large amount of memory. You might even do this on purpose to test the capacity of your system - attempt to allocate larger and larger blocks to see how far you go before you fail. Such a function may be useful to give scalability, for example if you want a large memory cache and are deciding how much you can use. (Perhaps half of the amount available before the bad_alloc occurred).

    Code:
    size_t capacity = 1;
    unsigned char * block;
    try
    {
       while ( capacity )
       {
           block = new unsigned char[capacity];
           delete [] block;
           capacity *= 2;
       }
      // block ends if it wraps round and never fails
      std::cout << "new never failed " << std::endl;
    }
    catch ( const bad_alloc & )
    {
        std::cout << "new failed on  " << capacity << std::endl;
    }
    Note this may not work on Linux which does not throw bad_alloc on a failed allocation, but simply blows up later. On this occasion you are not trying to use the memory so it probably won't blow up but you'll get "new never failed".

  4. #4
    Join Date
    Feb 2005
    Location
    "The Capital"
    Posts
    5,306

    Re: Catching bad_alloc Exceptions

    David, you need smart pointers to handle so many dynamic allocations otherwise the code will look so messy and it is very prone to getting leaks. And still better using vectors - but as you mention you want to keep that aside for some self learning read ahead.

    As for finding out which allocation failed - After initializing all the pointers to NULL and then calling the allocation routines and inside the catch block you do something like this:
    Code:
          if (ptr1){
                //send out a message/write a log file/write to cout that allocation for ptr1 was done successfully.
                cout << "allocation for ptr1 was done successfully ";  
                delete[] ptr1;
                ptr1 = NULL;
          }
          if (ptr2){
                cout << "allocation for ptr2 was done successfully " ; 
                delete[] ptr2;
                ptr2 = NULL;
          }
    To get to know how much was being allocated and what size caused the failure - NMTop40's suggestion would help you. Regards.

  5. #5
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Catching bad_alloc Exceptions

    Quote Originally Posted by exterminator
    David, you need smart pointers to handle so many dynamic allocations otherwise the code will look so messy and it is very prone to getting leaks. And still better using vectors - but as you mention you want to keep that aside for some self learning read ahead.
    Strange that something that complicated would be for self learning. This would have sufficed:
    Code:
    double *pdouble1 = 0;
    double *pdouble2 = 0;
    int main()
    {
         try
         {
              pdouble1 = new double [100000];
              pdouble2 = new double [100000];
              delete [] pdouble1;
              delete [] pdouble2;
        }
        catch  (const std::bad_alloc& )
        {
                // whatever
         }
    }
    David, one word of advice -- please use vectors for what you're trying to do. If you want to learn how try/catch and std::bad_alloc work, you don't need to write (or mess up) an entire application for learning purposes (see the code above).

    Regards,

    Paul McKenzie

  6. #6
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: Catching bad_alloc Exceptions

    In Paul's code, you would have to delete[] the first pointer in the catch block if the second one threw.

  7. #7
    Join Date
    Jan 2006
    Location
    Houston
    Posts
    29

    Re: Catching bad_alloc Exceptions

    Quote Originally Posted by Paul McKenzie
    David, one word of advice -- please use vectors for what you're trying to do. If you want to learn how try/catch and std::bad_alloc work, you don't need to write (or mess up) an entire application for learning purposes (see the code above).

    Regards,

    Paul McKenzie

    Thanks for the advice, Paul; I intend to take it, and will edit my code to use vectors.

    Some background:
    I have translated several numerical linear algebra routines from FORTRAN to C++ to Javascript and posted them online. Many people have contacted me to request the C++ source code, and I intend to supply it by posting it online. However, I would first like to polish it up (my code still uses the check for new returning NULL).

    In the course of browsing several forums, reading books, etc., concrete examples of dynamic arrays for numerical applications seemed pretty hard to find—so I decided to post my own:

    http://www.akiti.ca/DynamicArraysIntro.html

    (An example using vectors will be written and posted soon.)

    These pages will remain up; if anybody learns from them, wonderful. And if you have any suggestions for how the code might be further polished, please feel free to offer constructive criticism.

    Once these pages are finalized, I will continue with my original goal: re-coding the existing routines using vectors (and then posting that code online too).

    Regards,


    David

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured