Why does my program end when it's in the second loop of try catch?

So here's how the error occurs, first I type in 2.2 or any error that is not accepted by my try catch, I get prompted with the error message and it continues on to the next line which is to loop the whole thing again. Problem is after catching the error and bringing the user to the function, the next time I enter a value that is accepted, the program just ends abruptly. Any idea why?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
string flavour_function()
{
double input;
char error = 'a';
			
cout<<"Choose between 3 flavours\n";
cout<<"[1] Strawberry\n";
cout<<"[2] Chocolate\n";
cout<<"[3] Vanilla\n";
			
try
{
	cout<<"Enter an option\n";
	cin>>input;
	if(!cin)
		throw error;
	if(cin.peek() != '\n')
	{
		throw error;
	}
	if(input<=0 || input > 3)
	{
		throw -1;
	}
	if(static_cast<double>(static_cast<int>(input)) != input)
	{
		throw -1;
	}
}
catch(int)
{
	cout<<"===============================\n";
	cout<<"Error, numbers not within range\n";
	cout<<"===============================\n";
	flavour_function();
}
catch(...)
{
	cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout<<"==============================\n";
	cout<<"Error, numbers must be numeric\n";
	cout<<"==============================\n";
	flavour_function();
}
		
if(input ==1)
{
	return "Strawberry";
					
}
else if(input ==2)
{
	return "Chocolate";
						
}
else if(input ==3)
{
	return "Vanilla";
					
}							
}

int main()
{
	string flavour;
	flavour=flavour_function();
	cout<<flavour;
}
You call flavour_function() recursively, but ignore its result, flowing out of the catch block with the invalid choice made in the current stack frame.
Last edited on
I would want to know why did you purposely remove the include and using lines from your code.
In order to test your issue we'll need to take time to insert those exact same lines back (which is not trivial)

your error is explained by this
In function ‘std::string flavour_function()’:
warning: control may reach end of non-void function [-Wreturn-type]

if you don't understand the message, we can explain it; but don't complain about an erroneous program when you willfully ignored the warnings.


> it continues on to the next line which is to loop the whole thing again.
your code could benefit from an actual loop.
also, ¿why do you throw exceptions when you are going to handle them in the same function?
@mbozzi @ne555 , sorry I don't understand anything you guys just said, pretty new to try catch and variable type validation, would appreciate some pointers or solutions.
You could have used a debugger to understand your code's behavior.

Take a look at this snippet. Do you understand why it's wrong? Assume that extract_int() can fail, but only a few times in a row.
1
2
3
4
5
6
7
int get_number()
{ 
  if (int it; extract_int(std::cin, it))
    return it;
 
  get_number(); // recurse, ignoring the result
}


(The exact same problem is in your code.)
Last edited on
And ...

What's with lines 3 and 25 in the OP?

This, perhaps, is not a good example for exceptions. This could be easily handled with a switch inside a while loop.

Why have you not seemed to have taken on board the advice given in your previous topics?

There's a simple reason why the code doesn't work - Follow me into the darkness.

After you throw and catch an exception, you re-call the function from within it. Once the user does enter a number you want, you'll successfully reach your if statements and return the desired string, but it wont return to int main! It'll instead return to the spot where the function was called! Which is within one of its own exceptions.

To explain in more depth, the "return "Whatever"" will return that value to where ever it was called from. So if you throw an exception and then call the function again, that next iteration will always send the return value BACK into the exception that called it to begin with.

Once it's done returning values to itself, the function will return to the point where it first called itself and try to finish that iteration (the iteration that actually tries to return something to int main). However, by then input is equal to the first input, which we already know was wrong. This is because every time you call the function, the function makes a brand NEW "double input", and its value will not carry over to the original "input" variable. The function then skips over the if statements and sends nothing back to int main.

Once nothing is sent back to int main, flavour is never initialized, you try to output it, the operating system shuts your program down.

Here's code where that wont happen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <string>
using namespace std;

string flavour_function()
{
	start:
	double input;
	char error = 'a';

	cout << "Choose between 3 flavours\n";
	cout << "[1] Strawberry\n";
	cout << "[2] Chocolate\n";
	cout << "[3] Vanilla\n";

	try
	{
		cout << "Enter an option\n";
		cin >> input;
		if (!cin)
			throw error;
		if (cin.peek() != '\n')
		{
			throw error;
		}
		if (input <= 0 || input > 3)
		{
			throw - 1;
		}
		if (static_cast<double>(static_cast<int>(input)) != input)
		{
			throw - 1;
		}
	}
	catch (int)
	{
		cout << "===============================\n";
		cout << "Error, numbers not within range\n";
		cout << "===============================\n";
		goto start; //Instead of a recursive call, Simply Start Over The Function
	}
	catch (...)
	{
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "==============================\n";
		cout << "Error, numbers must be numeric\n";
		cout << "==============================\n";
		goto start;
	}

	if (input == 1)
	{
		return "Strawberry";

	}
	else if (input == 2)
	{
		return "Chocolate";

	}
	else if (input == 3)
	{
		return "Vanilla";

	}
}

int main()
{
	string flavour;
	flavour = flavour_function();
	cout << flavour;
}


^This uses goto, which most recommend not to use.

Here's another way to solve the issue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <string>
using namespace std;

string flavour_function(double &input) // use "&" to alter the actual variable rather than send a copy of it
{
	//double input; Comment it out here
	char error = 'a';

	cout << "Choose between 3 flavours\n";
	cout << "[1] Strawberry\n";
	cout << "[2] Chocolate\n";
	cout << "[3] Vanilla\n";

	try
	{
		cout << "Enter an option\n";
		cin >> input;
		if (!cin)
			throw error;
		if (cin.peek() != '\n')
		{
			throw error;
		}
		if (input <= 0 || input > 3)
		{
			throw - 1;
		}
		if (static_cast<double>(static_cast<int>(input)) != input)
		{
			throw - 1;
		}
	}
	catch (int)
	{
		cout << "===============================\n";
		cout << "Error, numbers not within range\n";
		cout << "===============================\n";
		flavour_function(input);
	}
	catch (...)
	{
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "==============================\n";
		cout << "Error, numbers must be numeric\n";
		cout << "==============================\n";
		flavour_function(input);
	}

	if (input == 1)
	{
		return "Strawberry";

	}
	else if (input == 2)
	{
		return "Chocolate";

	}
	else if (input == 3)
	{
		return "Vanilla";

	}
}

int main()
{
	double input; // Declare here
	string flavour;
	flavour = flavour_function(input); // give as argument here
	cout << flavour;
}


^In THIS code, I keep the recursive aspect but keep the variable input from continuously copying itself. Now, every time input is changed, the actual variable is changed, and when you reach the end of your exceptions (when the user finally enters correct input), input will reflect that newest number and set off an if statement to return to int main.
Last edited on
Hello mrtammy2008,

@mbozzi @ne555 , sorry I don't understand anything you guys just said, pretty new to try catch and variable type validation, would appreciate some pointers or solutions.


The try/catch has it use like when you used it with the "stoi()" function. When you changed "input" to a numeric variable the try/catch can work, but I see it as overkill and more than you need.

Lets start with variables:

An "int" will hold a number. This is a whole number only like 1, 10, 100, 25.

A "double" will hole a floating point number and this can also be just a whole number like 10.25, 15.012, 2.0.

So when you define "input" as a "double" you are saying that "2.2" is an acceptable number. The you are using the try/catch to say that this is unacceptable input.

What you may not understand is that if you define "input" as an "int" and enter "2.2" it will store the "2", as a whole number, in the int and drop the ".2" because it is not an integer. This can be used to your advantage.

Using the try/catch can work, but I would consider leaving it until later. As it has been pointed out calling the function recursively and not using the returned value of the function is giving you a problem. This can be replaced using a do/while or while loop for most of the function and only returning a valid input.

As an alternative here is an example for you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <limits>
#include <string>

std::string flavour_function()
{
	int input; // <--- Does not need to be a "double".
	//char error = 'a'; // <--- Not needed.

	std::cout << "Choose between 3 flavours\n";
	std::cout << "[1] Strawberry\n";
	std::cout << "[2] Chocolate\n";
	std::cout << "[3] Vanilla\n";
	std::cout << "[4] Exit\n";
	std::cout << "Enter an option: "; // <--- Removed the '\n' and added ": ".
	std::cin >> input;  // <--- Will accept 2 or 2.2, but will fail if the first character is a letter.

	while (!std::cin || (input < 0 || input > 4))
	{
		if (!std::cin)
		{
			std::cout << "\n==============================\n"; // <--- Added '\n' at the beginning of the string.
			std::cout << "Error, numbers must be numeric\n";
			std::cout << "==============================\n" << std::endl;

			std::cin.clear();
			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.

			std::cout << "Enter an option: "; // <--- Removed the '\n' and added ": ".
			std::cin >> input;
			std::cout << std::endl;
		}
		else
		{
			std::cout << "\n===============================\n"; // <--- Added '\n' at the beginning of the string.
			std::cout << "Error, numbers not within range\n";
			std::cout << "===============================\n" << std::endl;

			std::cout << "Enter an option: "; // <--- Removed the '\n' and added ": ".
			std::cin >> input;
			std::cout << std::endl;
		}
	}

	switch (input)
	{
		case 1:
			return "Strawberry";
		case 2:
			return "Chocolate";
		case 3:
			return "Vanilla";
		case 4:
			return "";
	}

	
}

int main()
{
	std::string flavour;
	
	do
	{
		flavour = flavour_function();
		std::cout << flavour << '\n' << std::endl;

	} while (flavour.length());

	
	return 0;
}

I used a switch, but you can use the if statements that you started with just as easy. There are no "break" statements in the switch because the returns would prevent you from reaching the break statements. And there is no "default:" because the value of "input" would be 1 - 4 .

In "main" the while condition may appear a bit strange. Weather it is a while condition or the middle part of a for loop the expression is evaluated to either "0" (zero) false or something greater than zero which is considered true. So when the function returns an empty string to end the program "flavour.length()" evaluates to false (0) and the while condition ends. Anything else the string has a length greater than zero, so the do/while loop continues.

As an alternative I think this will do a better job than the try catch. And since it does not call the function recursively you eliminate that problem.

Give it a try. Any questions let me know.

Hope that helps,

Andy
Topic archived. No new replies allowed.