Exception expected (C++)

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Nepomuk
    Recognized Expert Specialist
    • Aug 2007
    • 3111

    Exception expected (C++)

    I'm learning C++ at the moment and in my textbook there is the following example:
    Code:
    #include <iostream>
    using namespace std;
    
    int main() {
    	char *puffer;
    	int mb;
    	try {
    		cout << "How many MB should be reserved? ";
    		cin >> mb;
    		puffer = new char[256 * 4 * 1024 * mb];
    		if(puffer == NULL)
    			throw "Error with memory allocation!";
    	}
    	catch (char * str) {
    		cout << "Exception: " << str << endl;
    		return 1;
    	}
    	cout << "Success!" << endl;
    	return 0;
    }
    Now, what should happen according to the book is, that if I try to reserve more space than RAM and Swap space together, it should throw that exception. However, when I try to allocate more memory than available, the following message apears:
    Code:
    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    Aborted
    In case it makes any difference, I'm using gcc 4.2.4 on a Linux system and have 3GB of memory available (RAM + Swap).

    I am guessing, that this example is either wrong in general or other Compilers make it react differently. Could someone here enlighten me?

    Greetings,
    Nepomuk
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    If a bad_alloc exception is thrown, then you need to catch a bad_alloc.

    bad_alloc is a derived class of exception so you could also catch an exception.

    Be sure to do this by reference. That is, a) catch a bad_alloc&, or b) catch an exception&. You can then call the what() method to view the string.

    Comment

    • JosAH
      Recognized Expert MVP
      • Mar 2007
      • 11453

      #3
      ... or you can install your own 'new_handler' that is supposed to automagically cough up some more memory. If all else fails you can call the new operator with a second parameter 'nothrow' that causes new not to throw an exception. Read this.

      kind regards,

      Jos

      Comment

      • Nepomuk
        Recognized Expert Specialist
        • Aug 2007
        • 3111

        #4
        OK, so I added this:
        Code:
        catch(bad_alloc &b) {
        	cerr << "Exception : " << b.what() << endl;
        	return 1;
        }
        And the output is:
        Code:
        Exception : std::bad_alloc
        for the input 999999999999999 999999999999999 99.

        With testing I found that it's the puffer = new char[...] part, that throws the exception. However, if I put that in a try-catch-statement like this:
        Code:
        try {
        	puffer = new char[256 * 4 * 1024 * mb];
        } catch(bad_alloc &b){cerr << "bad_alloc" << endl;}
        if(puffer == NULL) //...
        it just finishes normally for that output, although in my opinion it shouldn't. No sign of a "bad_alloc" output there.

        What the author obviously intended is, that it doesn't assign anything at all. Could you give me an example, where it really doesn't? Or does the new operator not work like that?

        Greetings,
        Nepomuk

        Comment

        • weaknessforcats
          Recognized Expert Expert
          • Mar 2007
          • 9214

          #5
          So what was the value of mb?

          If you caught a bad_alloc on those 9999's then you should catch a bad_alloc when one this thrown.

          BTW, it's always a good to catch(...) just to be sure an throw doesn't sneak by you.

          If yo do that using your second example is an exception thrown? If so, change the catch bad_alloc& to catch exception&. Then when you call what() you should see the string and that should report what kind of excption it is.

          Comment

          • Nepomuk
            Recognized Expert Specialist
            • Aug 2007
            • 3111

            #6
            OK, now I have this:
            Code:
            #include <iostream>
            using namespace std;
            
            int main() {
            	char *puffer;
            	int mb;
            	try {
            		cout << "How many MB should be reserved? ";
            		cin >> mb;
            		cout << "MB: " << mb << endl;
            		try {
            			puffer = new char[256 * 4 * 1024 * mb];
            		} catch(exception &e){cout << "This was thrown: " << e.what() << endl;}
            		if(puffer == NULL)
            			throw "Error with memory allocation!";
            		//else
            		//	cout << "Puffer address: " << &puffer << endl;
            	}
            	catch (char * str) {
            		cout << "Exception: " << str << endl;
            		return 1;
            	}
            	catch(bad_alloc &b) {
            		cerr << "Exception : " << b.what() << endl;
            		return 1;
            	}
            	catch(exception &e) {
            		cerr << "Other Exception: " << e.what() << endl;
            	}
            	catch(...) {
            		cerr << "Some Exception was thrown." << endl;
            	}
            	/*catch(std::bad_alloc b) {
            		cout << "Exception: std::bad_alloc" << endl;
            		return 1;
            	}
            	catch (...) {
            		cout << "Other Exception" << endl;
            		return 1;
            	}*/
            	cout << "Success!" << endl;
            	return 0;
            }
            So, here's the program run:
            Code:
            How many MB should be reserved? 999999999
            MB: 999999999
            This was thrown: std::bad_alloc
            Success!
            So, obviously it catches the Exception in the first try-catch now. But something is allocated anyway, because puffer isn't NULL. I checked and if you ask for &puffer to be printed, an actual address is printed.

            So, the questions remain:
            1. Why wasn't the exception caught by the catch(bad_alloc &b)?
            2. What does new do here? Or should I ask: Why isn't puffer NULL?

            Thanks for the help so far, it has already helped me understand some things. :-)

            Greetings,
            Nepomuk

            Comment

            • JosAH
              Recognized Expert MVP
              • Mar 2007
              • 11453

              #7
              Originally posted by Nepomuk
              This was thrown: std::bad_alloc
              Success! So, obviously it catches the Exception in the first try-catch now. But something is allocated anyway, because puffer isn't NULL.
              It's a local variable; locals aren't (implicitly) initialized to zero (null).

              kind regards,

              Jos

              Comment

              • Nepomuk
                Recognized Expert Specialist
                • Aug 2007
                • 3111

                #8
                Jos, you solved the mystery! I moved that char *puffer; out of the main method and it works as it should do!

                However I wonder: Why so? Why are local variables treated differently than global ones in this way? I'm sure there's a reason this difference was chosen and I'd love to understand, what this reason is.

                Greetings,
                Nepomuk

                Comment

                • Banfa
                  Recognized Expert Expert
                  • Feb 2006
                  • 9067

                  #9
                  That is easy, global variables are allocated in 1 large chunk, it is easy for the program during startup to just zero that chunk of memory and have no real effect on the execution of the program apart from slowing up start-up (although this can be be significant see below*). However to initialise all local variables to 0 would require code at the start of each function to do it every time the function was executed. This would have a far more serious effect on execution speed.

                  BTW best practivce would have been to initialise your pointer to NULL rather than move it out of main and make it a global variable.


                  * Start-up time IS significant

                  I worked on a project once, a professional digital satellite receiver. We got a message from the factory that 60% - 70% of the units manufactured didn't start. Investigation showed that they in fact did not not start but that the hardware watchdog chip kept on reseting the main processor before it had started properly so it was in a reset loop. Checking it was found that the watchdog chip had a fixed timeout of 1.25s +- 0.75s (it was a cheap low quality part) or 0.5 - 2 seconds and that units could be fixed by replacing the watchdog chip.

                  Thus the problem was passed to me, the first place the watchdog was kicked was main, right at the top so I measured the time it took for the code to get into main... 1.6 seconds. That was clearly the problem so I got out the assembler manual and delved into the c start-up code for the processor. I was successfully able to enable the watchdog I/O pin and kick it at various places during c start-up to mitigate the variable watchdog hardware. However 1 problem I was unable to solve which was initialisation of static (global) data. This was atomic (a single instruction) and it took 0.6 seconds. Not being able to do anything about this I checked my code in and told my manager to tell the factory to expect about 7% of the units to still fail, which they did.

                  Comment

                  • JosAH
                    Recognized Expert MVP
                    • Mar 2007
                    • 11453

                    #10
                    Originally posted by Banfa
                    Thus the problem was passed to me, the first place the watchdog was kicked was main, right at the top so I measured the time it took for the code to get into main... 1.6 seconds.
                    Wasn't that watchdog interval time programmable or couldn't you simply turn that darn thing off? (those Atmel thingies have that capability (thank god))

                    kind regards,

                    Jos

                    Comment

                    • Banfa
                      Recognized Expert Expert
                      • Feb 2006
                      • 9067

                      #11
                      No to the interval was not programmable, just very variable. Like I said it was a cheap part.

                      We didn't want to to disable it. The watchdog chip couldn't be switched off but there was a zero ohm resistor on the output that could be moved to connect the watchdog input to the 50Mhz clock.

                      However since the unit was destined for various places around the world some of them without good access, a few were situated at sites where the only access was by helicopter, having the watchdog active was considered necessary to ensure the units remained running and lots of expensive helicopter trips were not required to just reboot the thing.

                      Of course on our development boards we moved the resistor otherwise you were guaranteed a reset while using the symbolic debugger, and in fact while trying to download your code.

                      Comment

                      • JosAH
                        Recognized Expert MVP
                        • Mar 2007
                        • 11453

                        #12
                        Originally posted by Nepomuk
                        Jos, you solved the mystery! I moved that char *puffer; out of the main method and it works as it should do!

                        However I wonder: Why so? Why are local variables treated differently than global ones in this way? I'm sure there's a reason this difference was chosen and I'd love to understand, what this reason is.
                        Speed; global variables need only to be initialized when your process starts; local variables need to be initialized every time the function is called. Java does the same: you need to explicitly initialize local variables. The only difference is that C and C++ compilers just don't care. You could've explicitly initialized your local pointer to NULL.

                        kind regards,

                        Jos

                        Comment

                        • Nepomuk
                          Recognized Expert Specialist
                          • Aug 2007
                          • 3111

                          #13
                          Originally posted by Banfa
                          That is easy,...
                          Originally posted by JosAH
                          Speed; global variables need...
                          Great, thanks Banfa and Jos for explaining in such detail. I'll try to remember all of that. ^^
                          Originally posted by Banfa
                          BTW best practivce would have been to initialise your pointer to NULL rather than move it out of main and make it a global variable.
                          Yes, it would have been best practice, but this way I understand a bit more about how the language works. I know that in C++ global variables should be avoided where possible and in any programs that I write my self, I'll remember all of this advice. But for the learning experience, I might even checkout how goto works. (Not that I'm EVER going to use it, I'm just curious. :-D)

                          Greetings,
                          Nepomuk

                          Comment

                          • JosAH
                            Recognized Expert MVP
                            • Mar 2007
                            • 11453

                            #14
                            Originally posted by Nepomuk
                            Yes, it would have been best practice, but this way I understand a bit more about how the language works.
                            C, C++ and Java work alike: global variables are implicitly initiailized to all bits zero, local variables aren't initialized. It's the Java compiler that checks whether or not local variables are explicitly initialized (or assigned to) before their value is read somewhere. Java 'global' variables are the static class variables.

                            kind regards,

                            Jos

                            Comment

                            • Nepomuk
                              Recognized Expert Specialist
                              • Aug 2007
                              • 3111

                              #15
                              Well, you live and learn! Thanks for explaining. :-)

                              Greetings,
                              Nepomuk

                              Comment

                              Working...