Search code examples
c++vector

How do I catch the bad_alloc exception when the user inserts a char value into a int vector


I'm kinda new to C++ (and programming, in general). Today I was learning about exceptions and try...catch classes, and wanted to use them in a very frequent problem I run into: ending an input request to a vector when the user inserts a value that isn't the same type as the vector (for example, user inserts a letter instead of a number).

This is the kind of program I was testing, but the vector gets bloated with 0s

// The program calculates the sum of the even numbers and the product of the odd ones
#include <iostream>
#include <vector>
using namespace std;

int main(){

  vector<int> list;
  int even_sum = 0, odd_product = 0, input = 0;

  cout << "Insert numbers, anything else will close the request \n";

  while(true){

    try{
      cin >> input;
      list.push_back(input);
    }
    
    catch(...){
      break;
    }

  }


  for(int i = 0; i < list.size(); i++){
    if(list[i] % 2 == 0){
      even_sum += list[i];
    }
    else{
      odd_product *= list[i];
    }
  }

  cout << "Here's the sum " << even_sum << endl;
  cout << "Here's the product " << odd_product << endl;
}```

The idea is to end the loop when the user inserts a value that isn't the same type as the vector.


Solution

  • Well... You are catching all exceptions using catch(...) and then breaking out of the loop. This approach doesn't differentiate between different types of exceptions, and it also doesn't prevent invalid input from being added to the vector.

    To actually end the loop when the user inserts a value that isn't the same type as the vector, you can use a more "specific exception handling approach". Specifically, you can catch std::istream::fail exceptions that occur when the input doesn't match the expected type (in this case our little integer).

    #include <iostream>
    #include <vector>
    #include <stdexcept>
    #include <limits>
    
    int main() {
        std::vector<int> list;
        int even_sum = 0, odd_product = 1, input = 0;
    
        std::cout << "Insert numbers, anything else will close the request" << std::endl;
    
        while (true) {
            try {
                if (!(std::cin >> input)) {                                  // Check for input validity
                    if (std::cin.eof()) {                                              
                        break;                                               // End of input reached
                    } else {                                    
                        throw std::runtime_error("Invalid input");           // Input didn't match the expected type (integer)
                    }
                }
                list.push_back(input);
            } catch (const std::exception& e) {
                std::cout << "Exception caught: " << e.what() << std::endl;
                std::cin.clear();                                            // Clear the error state
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Ignore the invalid input
                break;                                                       // Break the loop when invalid input is encountered
            }
        }
    
        for (int i = 0; i < list.size(); i++) {
            if (list[i] % 2 == 0) {
                even_sum += list[i];
            } else {
                odd_product *= list[i];
            }
        }
    
        std::cout << "Here's the sum: " << even_sum << std::endl;
        std::cout << "Here's the product: " << odd_product << std::endl;
        return 0;
    }
    

    This code might differ and look a little like spaghetti but it's not that complicated.

    Entire try/catch scope performs input validation and error handling. It checks if the input is valid and handles cases where it's not. If invalid input is detected within if (!(std::cin >> input)), it throws a std::runtime_error, clears the input stream's error state std::cin.clear();, ignores any remaining input on the line std::cin.ignore(std::numeric_limits<std::streamsize>::max() (in case we have a situation of a mixed input like "2a" or "239a"), and breaks out of the loop.

    Also never forget to add return 0; at the end of your main() function, otherwise change it's return type to void.

    I also changed the initialization of odd_product to 1. This change ensures that if no odd numbers are provided as input, the initial value of 1 won't affect the final result. 0 would cause problems since (multiplying by 0 would always result in 0).

    I hope that helps, feel free to reach out.