1 00:00:05,360 --> 00:00:09,120 In this video, we'll see a use case that's commonly seen in c++, 2 00:00:09,120 --> 00:00:11,620 and we'll see how we can use exception handling with it. 3 00:00:12,500 --> 00:00:16,200 Suppose we have a function. Of course, this will also work with methods. 4 00:00:16,560 --> 00:00:19,160 And that function is called calculate average. 5 00:00:19,860 --> 00:00:24,110 It expects a sum of integers that we can assume has already been calculated somewhere else, 6 00:00:24,470 --> 00:00:26,830 and the total number of elements used to get that sum. 7 00:00:27,630 --> 00:00:31,630 And what we want to do is determine the average and return it as a double from this function, 8 00:00:32,430 --> 00:00:34,130 pretty straightforward stuff. 9 00:00:34,130 --> 00:00:37,330 Also notice that we don't want integer division 10 00:00:37,330 --> 00:00:40,480 since we want to return a double, so we're using a static cast 11 00:00:40,480 --> 00:00:43,180 to convert one of the division operands to a double. Cool. 12 00:00:43,180 --> 00:00:47,840 So, so far pretty easy, right? Well, almost. What if total is 0? 13 00:00:48,440 --> 00:00:50,440 What do we do? What do we return? 14 00:00:50,440 --> 00:00:54,040 We could return 0, but 0 might be a valid average. 15 00:00:54,040 --> 00:00:58,040 We could return negative 1,but negative 1 might be a valid average. 16 00:00:58,040 --> 00:01:00,920 We could return some other double that represents an error, 17 00:01:00,920 --> 00:01:04,519 but which one since just about any double could be a valid average. 18 00:01:05,069 --> 00:01:07,870 We could rewrite this function to return a Boolean 19 00:01:07,870 --> 00:01:10,170 and that Boolean would indicate success, right. True if it worked, false if it didn't, 20 00:01:10,170 --> 00:01:13,830 but then how do we return the average. 21 00:01:13,830 --> 00:01:17,490 We'd have to use a reference parameter and do it that way or use a tuple, 22 00:01:17,490 --> 00:01:20,590 makes the function really clunky to use. 23 00:01:20,990 --> 00:01:25,290 So let's see how we can write this function using exceptions and exception handling. 24 00:01:26,790 --> 00:01:31,490 We can rewrite the function without changing its interface and still provide a guarantee 25 00:01:31,740 --> 00:01:35,640 that the function will not divide by 0 by throwing an exception. 26 00:01:36,140 --> 00:01:38,820 First we check if total is equal to 0. 27 00:01:38,820 --> 00:01:41,420 If it is we, don't want to do the division. 28 00:01:41,820 --> 00:01:43,420 Instead, we throw 0. 29 00:01:43,820 --> 00:01:48,810 In this case, we could throw anything and c++ allows us to throw just about any type. 30 00:01:49,010 --> 00:01:52,510 But let's use 0 again which is an integer, and we've done it previously. 31 00:01:52,510 --> 00:01:57,010 If we throw the exception, the division will not happen, and the function will terminate. 32 00:01:57,510 --> 00:02:00,710 Now c++ will try to find an exception handler 33 00:02:00,710 --> 00:02:03,010 to catch that integer that the function threw. 34 00:02:03,010 --> 00:02:07,310 How does it do that. Well, the handler isn't in this function so where else might it be. 35 00:02:07,860 --> 00:02:10,860 It may not exist at all, in which case, the program will terminate. 36 00:02:11,660 --> 00:02:13,860 But if an exception handler exists, 37 00:02:13,860 --> 00:02:18,060 it must be in one of the functions on the call stack that called this function, right. 38 00:02:18,210 --> 00:02:21,570 And c++ will unwind the stack looking for it. 39 00:02:21,570 --> 00:02:23,570 We'll see how this works in a few videos. 40 00:02:24,070 --> 00:02:28,570 So let's see how this function might be called in a way that would allow us to deal with the exception. 41 00:02:29,870 --> 00:02:33,420 Now this code could exist in any function anywhere in your program. 42 00:02:33,420 --> 00:02:38,410 Notice that we have a try block. And in the try block, we call the calculate average function. 43 00:02:39,310 --> 00:02:41,670 We know this function might throw an exception. 44 00:02:41,670 --> 00:02:44,170 And if it does, we'll deal with it in the catch block. 45 00:02:44,670 --> 00:02:47,670 But first let's see what happens if no exception is thrown. 46 00:02:48,030 --> 00:02:51,530 Again, we're assuming that sum and total have been declared and initialized. 47 00:02:52,090 --> 00:02:56,390 In this case, average is assigned the return value from the function and we display it. 48 00:02:56,790 --> 00:03:00,550 Then we skip the catch block completely since no exceptions were thrown, 49 00:03:00,550 --> 00:03:03,350 and we execute the last statement that displays by. 50 00:03:04,450 --> 00:03:07,110 If calculate average does throw an exception, 51 00:03:07,110 --> 00:03:10,510 then the remaining code in the try block is not executed. 52 00:03:10,510 --> 00:03:12,770 So we do not do the division by 0. 53 00:03:13,760 --> 00:03:17,120 And c++ searches for a catch block that expects an integer 54 00:03:17,120 --> 00:03:19,720 since that's the type of the exception that was thrown. 55 00:03:20,220 --> 00:03:21,720 In this case, it finds it. 56 00:03:21,920 --> 00:03:25,580 Notice that our catch handler expects a reference to an integer. 57 00:03:25,580 --> 00:03:29,580 Again, best practice is to throw by value and catch by reference. 58 00:03:29,580 --> 00:03:31,080 We'll talk more about that later. 59 00:03:31,630 --> 00:03:35,620 So in this case, the code in the body of the catch handler executes, 60 00:03:35,620 --> 00:03:37,980 displays an error message to the error stream. 61 00:03:38,480 --> 00:03:42,840 When the catch block completes, we transfer to the last statement, and we display by. 62 00:03:42,840 --> 00:03:46,200 That's it. It's possible to have multiple catch handlers 63 00:03:46,200 --> 00:03:49,700 as well as catch all handlers that will catch any type of exception. 64 00:03:49,700 --> 00:03:53,060 We'll do that in the next video. But first, let's head over to the IDE, 65 00:03:53,060 --> 00:03:55,420 and we'll rewrite the miles per gallon example 66 00:03:55,420 --> 00:03:58,020 as a function and use exception handling with it. 67 00:03:59,120 --> 00:04:02,980 Okay. So I'm back in the IDE. Again, I'm in the section 18 workspace, 68 00:04:02,980 --> 00:04:05,780 and I'm in the MPG function project. 69 00:04:06,440 --> 00:04:10,440 What I've done here is I've taken the calculation for miles per gallon, 70 00:04:10,440 --> 00:04:11,840 and I've made it a function. 71 00:04:11,840 --> 00:04:16,500 So in this case, it expects miles and gallons which are both integers and returns the double, 72 00:04:16,500 --> 00:04:18,300 which is the miles per gallon. 73 00:04:18,300 --> 00:04:20,899 And I'm simply dividing miles by gallons. 74 00:04:20,899 --> 00:04:25,780 And again, I'm casting miles to a double so that we do double division and get an accurate result. 75 00:04:26,030 --> 00:04:30,580 That's it. My main is just like it was before the user enters the miles, the gallons, 76 00:04:30,580 --> 00:04:33,470 and the only difference now is that on line 19 right here. 77 00:04:33,470 --> 00:04:36,970 You can see that I'm calling calculate miles per gallon, 78 00:04:36,970 --> 00:04:39,770 and I'm passing in the user entered values. 79 00:04:39,770 --> 00:04:41,670 So let's run this as is 80 00:04:41,670 --> 00:04:44,870 without any exception handling, without any error checking at all. 81 00:04:44,870 --> 00:04:49,070 So we'll run this, and let's say I entered 120 miles 82 00:04:49,070 --> 00:04:50,070 and I entered 0. 83 00:04:51,270 --> 00:04:54,630 There's my result, which is infinity. That's not what I want. 84 00:04:54,630 --> 00:04:58,230 And we'll deal with that in just a sec. So 85 00:04:58,230 --> 00:05:00,590 we know that we don't want to divide by 0. So what 86 00:05:00,590 --> 00:05:04,890 we can do up here in the function is we can say if gallons 87 00:05:05,550 --> 00:05:06,540 is 0, 88 00:05:08,140 --> 00:05:12,240 we want to throw an exception. And we'll just throw -- again, we'll throw 0, 89 00:05:12,240 --> 00:05:13,940 which is a simple integer. 90 00:05:13,940 --> 00:05:17,140 Now let's run this. You'll see something that's a little bit different 91 00:05:17,140 --> 00:05:20,240 now. When I call calculate miles per gallon here 92 00:05:20,790 --> 00:05:24,890 and I use a 0 for the gallons,it's going to throw this exception. 93 00:05:24,890 --> 00:05:27,550 That exception is not being caught anywhere. 94 00:05:27,550 --> 00:05:31,210 So it's going to go all the way up to the top in my main, that's where I'm at now, 95 00:05:31,210 --> 00:05:34,710 and our program is going to terminate. It's going to terminate abnormally. 96 00:05:34,710 --> 00:05:37,710 So let's run this so you can see what that looks like. 97 00:05:38,370 --> 00:05:42,370 So again, I'm going to enter 120, and I'm going to enter 0 for the gallons. 98 00:05:42,370 --> 00:05:45,810 And you can see right there it says -- I'll cancel that, you can see it's 99 00:05:45,810 --> 00:05:48,410 terminate called after throwing an instance event. 100 00:05:48,410 --> 00:05:51,770 This application has requested the runtime to terminate 101 00:05:51,770 --> 00:05:55,270 it in an unusual way, a bad termination, right. 102 00:05:55,270 --> 00:05:58,270 Basically, an exception was thrown that was not handled, 103 00:05:58,270 --> 00:06:00,270 that will always terminate your program. 104 00:06:00,770 --> 00:06:03,970 So how do we handle that exception. Remember, 105 00:06:03,970 --> 00:06:06,770 the mile -- to calculate miles per gallon function up here 106 00:06:06,770 --> 00:06:10,970 has no clue what to do when its gallon is 0. All it knows is 107 00:06:10,970 --> 00:06:15,170 I can't do a divide by 0, and should i just print an error message? 108 00:06:15,170 --> 00:06:18,730 I don't know what to do, so someone else do it. I'm just throwing the exception. 109 00:06:18,730 --> 00:06:20,730 So what we can do down here is 110 00:06:20,730 --> 00:06:25,720 we can write a try block around this code that could potentially throw an exception. 111 00:06:25,720 --> 00:06:27,920 So let's do that. I'll say try, 112 00:06:29,420 --> 00:06:33,620 and I'll close off the try block here. And we'll indent this area right here. 113 00:06:33,620 --> 00:06:37,920 So I'm going to try to execute that function. If the function works properly, 114 00:06:37,920 --> 00:06:42,220 then I just print out miles per gallon. If that function throws an exception, 115 00:06:42,720 --> 00:06:46,520 then we're not going to divide, right, because it's thrown it before the division, 116 00:06:46,520 --> 00:06:49,880 it's not going to assign miles per gallon. Basically, the try block will stop, 117 00:06:49,880 --> 00:06:53,870 and it's going to look for a catch handler, right. So let's write the catch handler. 118 00:06:54,070 --> 00:06:56,270 Our catch handler looks kind of like this. 119 00:06:56,270 --> 00:07:00,470 What am I going to catch? Well, I'm going to catch an integer by reference. 120 00:07:02,370 --> 00:07:06,270 And right here, I'm simply going to print std cerr 121 00:07:06,270 --> 00:07:08,770 tried to divide by 0 or something like that. 122 00:07:11,760 --> 00:07:16,160 Okay. That's it. So you can see now that the error is detected in one place, 123 00:07:16,160 --> 00:07:19,040 and it's all in one file here just for instruction purposes. 124 00:07:19,040 --> 00:07:22,700 But this could be anywhere in your program, right. The error has been detected here, 125 00:07:22,700 --> 00:07:26,700 and it's been handled here. Okay. So let's run this now. 126 00:07:28,300 --> 00:07:30,900 And we'll do it -- again, 120 and 0 127 00:07:31,450 --> 00:07:35,450 try to divide by 0 by our program terminated normally. 128 00:07:35,450 --> 00:07:38,350 We handled the exception in a controlled manner, 129 00:07:38,350 --> 00:07:39,850 and that's really what it's all about. 130 00:07:40,400 --> 00:07:43,400 Okay. Now in this case, there could be some issues, right. 131 00:07:43,400 --> 00:07:46,760 We need to catch some other exceptions, and that's what we'll do in the next video. 132 00:07:46,760 --> 00:07:48,260 What if miles is negative, 133 00:07:48,920 --> 00:07:53,280 but that doesn't make sense. I traveled negative 100 miles per gallon. 134 00:07:53,280 --> 00:07:56,380 So we want to also throw an error if miles is negative 135 00:07:56,380 --> 00:07:59,880 or if gallons is negative for that matter, right. How can you have negative gallons? 136 00:07:59,880 --> 00:08:03,480 So in this case, we're just doing a simple test so we don't divide by 0. 137 00:08:03,480 --> 00:08:06,180 But in the other cases, which we'll do in the next video, 138 00:08:06,180 --> 00:08:10,380 we're going to check to make sure that we've got valid values here. So if miles is negative 139 00:08:10,380 --> 00:08:14,260 or gallons is negative, then my calculation cannot be correct. 140 00:08:14,260 --> 00:08:16,260 So we'll throw another exception there, 141 00:08:16,260 --> 00:08:19,560 and we'll catch multiple exceptions. So we'll do that in the next video.