int At(int i, int j) const {
try {
if (i >= m.size() || j >= m[0].size())
throw out_of_range("out_of_range");
return m.at(i).at(j);
}
catch (exception& e) {
cout << e.what() << endl;
}
}
int& At(int i, int j) {
try {
if (i >= m.size() || j >= m[0].size())
throw out_of_range("out_of_range");
return m.at(i).at(j);
}
catch (exception& e) {
cout << e.what() << endl;
}
}
int main() {
Matrix one, two(2, 3);
cout << two;
one.Reset(0, 0);
cout << one.At(4, 4);
return 0;
}
in this code must be printed exception: out_of_range, but in my case it is :
out_of_range
-244281
What are this number and how can I remove it from output?
If the exception is thrown, then the catch handler prints the message ("out_of_range") and then the function continues on like nothing happened.
The problem is that this "continue on" leads to the functions ending without you returning anything, leading to undefined behavior when you try to print this non-return value.
If you declare a function to return anything, the you must return something.
With that said, catching the exception in the At function makes no sense. And considering that one of the variants return a reference, it's very hard to return a "value" since you can't have "null" references.
The solution then is not to have the try-catch at all in the functions, but let the caller of the function handle any possible exception.
int& At(int i, int j) {
// ...
catch (exception& e) {
cout << e.what() << endl;
}
}
The exception is caught and printed ...and then At() returns normally.
Your compiler should've warned you about returning from a non-void function without returning a value.
In your main():
cout << one.At(4, 4);
So, now this attempts to interpreted the value returned from At() as a reference to some int. Nothing was returned, so this is undefined behavior, and you can get any random junk printed here. Or your program can crash. You have no logical expectations, any more.
Related
Does this quote from https://en.cppreference.com/w/cpp/language/function-try-block have a typo?
Reaching the end of a catch clause for a function-try-block on a destructor also automatically rethrows the current exception as if by throw;, but a return statement is allowed.
It seems hard to believe that a destructor automatically re-throws, when every article by every expert I've ever read says that destructors should never, ever throw under any circumstance. In fact, the example code above the quote shows an implicit throw from a constructor, not a destructor.
Therefore, I wonder, is the statement wrong and should have indicated that behavior for a constructor instead?
I had been reviewing this other StackOverflow article when I started thinking about this: C4297 warning in Visual Studio while using function-try-block (function assumed not to throw an exception but does). It already had an answer, but nobody questioned whether the quote was accurate in the first place.
The answer is no, it is not a typo.
The cppreference article did not show an example of a destructor function try block, so I crafted one myself and tested it. Below is the same code. I tested with Microsoft VS2019, using the v142 platform toolset and C++20 dialect.
If you execute this, an abort will be called, which is consistent with the warning that the compiler issues. This suggests that the function catch block does automatically re-throw, even for a destructor. If you uncomment the return statement, it will not throw. Although, I find that to be counter-intuitive, writing a return statement provides a workaround to prevent the implicit throw, just as the referenced StackOverflow article suggests.
#include <iostream>
#include <string>
struct S
{
std::string m;
S(const std::string& str, int idx) try : m(str, idx)
{
std::cout << "S(" << str << ", " << idx << ") constructed, m = " << m << '\n';
}
catch (const std::exception& e)
{
std::cout << "S(" << str << ", " << idx << ") failed: " << e.what() << '\n';
} // implicit "throw;" here
~S() try
{
if (m.length() > 5) {
throw std::exception("shouldn't have been that big!");
}
std::cout << "destroyed!" << std::endl;
}
catch (const std::exception& e)
{
//return;
}
};
int main()
{
S s1{ "ABC", 1 }; // does not throw (index is in bounds)
try
{
S s2{ "ABC", 4 }; // throws (out of bounds)
}
catch (std::exception& e)
{
std::cout << "S s2... raised an exception: " << e.what() << '\n';
}
try
{
S s3("123456", 0);
}
catch (std::exception& e)
{
std::cout << "S s2... raised an exception: " << e.what() << '\n';
}
}
I'm following an example code from Programming Principles and Practice Using C++ in one of the example for exception it shows this snippet of code
int main()
{
try {
vector<int> v; // a vector of ints
for (int x; cin >> x; )
v.push_back(x); // set values
for (int i = 0; i <= v.size(); ++i) // print values
cout << "v[" << i << "] == " << v[i] << '\n';
}
catch (const out_of_range& e) {
cerr << "Oops! Range error\n";
return 1;
}
catch (...) { // catch all other exceptions
cerr << "Exception: something went wrong\n";
return 2;
}
}
From what I understand it is suppose to catch out_of_range error and output "Oops! Range error". However, the Visual Studio 2019 shows this instead.
can someone explain why it shows me this
Does “try-catch” catches run time error (especially Out of Range error)?
No, in C++ most run time errors lead to Undefined Behavior, not exceptions. Only errors which explicitly throw exceptions can be caught.
std::vector<T>::operator[] does not specify that it throws an exception when you access out of bounds, it is just Undefined Behavior and anything can happen. It can even appear to work. When I try it here, there isn't any visible error : https://godbolt.org/z/Pcv9Gn8M9
If you want an exception on out of bounds access, std::vector<T>::at() does throw std::out_of_range.
For your test you should use v.at(i) instead of v[i]. Try it here : https://godbolt.org/z/szKxhjxhx.
I am analyzing part of code that was part of my lectures.
I have managed to compile it but I cannot understand:
why does my program output "Wyjatek" and 0 instead of "WyjatekNieoznaczony"?
I was pretty sure WyjatekNieoznaczony() should be thrown because a=0 and b=0 as well. Right now i am a little bit confused.
Could you help me, please?
class Wyjatek {};
class WyjatekBledny : public Wyjatek {};
class WyjatekNieoznaczony : public Wyjatek {};
double f(double a, double b) {
if (b == 0) {
if (a == 0)
throw WyjatekNieoznaczony();
else
throw WyjatekBledny();
}
return a / b;
}
double g(double a, double b) throw (int) {
try {
return f(a, b);
}
catch (WyjatekBledny) {
cout << "Wyjatek bledny" << endl;
throw 1;
}
catch (Wyjatek) {
cout << "Wyjatek" << endl;
}
catch (WyjatekNieoznaczony) {
cout << "Wyjatek nieoznaczony" << endl;
throw;
}
return 0;
}
int main()
{
double a = 0, b = 0;
try {
cout << g(a, b) << endl;
}
catch (...)
{
cout << "Inny wyjatek" << endl;
}
system("pause");
return 0;
}
Yes indeed a WyjatekNieoznaczony is thrown, but at the catch site, catch (Wyjatek) { is a match (due to the inheritance) so it's caught there.
A catch site is more like an if else block in behaviour - with each catch possibility being considered in the order they are written - rather than a switch block where you can put the labels in any order you like.
Note also that it's a good idea to catch exceptions by const reference than by value, else you can suffer the pitfalls of object slicing.
If you enabled (and read) compiler warnings, you would've encountered the following diagnostic:
warning: exception of type 'WyjatekNieoznaczony' will be caught [...] by earlier handler for 'Wyjatek'.
This basically means that WyjatekNieoznaczony, by inheriting from Wyjatek, will be first caught by catch(Wyjatek) clause, since it's convertible. The problem is that due to object slicing, it will lose its Nieoznaczonyness.
What I suggest is to reorder the catch clauses so the possibility of slicing disappears (in this case):
catch (WyjatekBledny) {
cout << "Wyjatek bledny" << endl;
throw 1;
}
catch (WyjatekNieoznaczony) {
cout << "Wyjatek nieoznaczony" << endl;
throw;
}
catch (Wyjatek) {
cout << "Wyjatek" << endl;
}
int mult (int a, int b)
{
if (a <= 0 || b <= 0) throw (" Your input is invalid. No zero");
int doub = a * b;
if (doub <= 0) throw (" Invalid value");
cout << "\\n" << doub;
return doub;
}
//code that gives values of num1 & num2//
try
{
mult(num1, num2);
}
catch (int error)
{
cerr << " Error ###$% invalid value";
}
The program works fine if both values (num1, numa2) are higher than 0, but if any value is less than 0 the program fails and doesn't throw the desired message. It just shows a default error.
Is it inproper use of the pre & post condition?
Is it the throw usage? (I have some doubts in how to use it, it might be that but I don't know)
throw (" Your input is invalid. No zero"); You are throwing a char *
catch (int error) But you are catching an int. This is a different type from char * so the exception is not caught and propagates up to the default handler.
The idiomatic way to do handle this would be to throw (std::runtime_error("Your input is invalid. No zero"));,
and catch (std::exception & e) { cerr << e.what(); }
You are throwing exceptions of type const char * but catching them as type int. To fix this, all you need to do is change:
catch (int error)
to:
catch (const char * error)
Live demo
Or, as QuestionC says, you can throw a std::runtime_error and catch that.
I want to know how to apply exception handling when the top variable reaches to a value -1 (no element left to pop). Currently, I am using cout to nofity the user about the stack underflow and returning 0, which is not a good practice. What improvement overall can be made to this pop function and how to notify user and handle the exception when stack reaches a state of underflow.
int Mystack::pop()
{
if (isEmpty())
{
std::cout << "Stack Underflow" << std::endl;
}
else
{
std::cout << "The popped element is" << A[top];
return A[top--];
}
return 0;
}
The Main Section :
case 4:
std::cout << "POP the element" << std::endl;
s1.pop();
break;
You can throw an out_of_range exception:
#include <stdexcept>
int Mystack::pop()
{
if (isEmpty())
throw std::out_of_range("Stack Underflow");
std::cout << "The popped element is" << A[top];
return A[top--];
}
On the client side:
void foo()
{
Mystack ms;
//...
try
{
ms.pop();
}
catch (const std::out_of_range& oor)
{
std::cerr << "Out of Range error: " << oor.what() << '\n';
}
}
Edit: As the comments below mentioned, you can also derive your own exception from std::exception. Here is a simple example:
#include <stdexcept>
struct myStackException : public std::exception
{
const char *what() const noexcept { return "Stack Overflow"; }
};
int Mystack::pop()
{
if (isEmpty())
throw myStackException();
std::cout << "The popped element is" << A[top];
return A[top--];
}
Live (dummy) example: http://ideone.com/ZyqiQ0
Re
” What improvement overall can be made to this pop function
You can
Make it void to make it more exception safe for other item types.
With the current design, if copying of the popped item fails, then there is no way to recover.
Remove internal output.
assert that the underflow doesn't occur, so that this can be caught in testing.
Thus,
void Mystack::pop()
{
assert( top > 0 );
--top;
}
Wow, what a simplification – and now more exception safe too!
As an alternative to the assert you can throw an exception. That's better than the original, but absolutely not better than the assert. It moves correctness issues into the runtime domain, to be handled and perhaps worked around by each caller site.
The benefit of using C++ exceptions is that error handling code can be separated from user code, alleviating the need for code to be littered with error handling code that is common in C programs. Throwing an exception also offers a solution to returning a invalid value in the error case
if( s1.pop() == 0 ){
// is this an error or not?
}
Exceptions can be added to your code like so, by taking advantage in the generic exceptions in the
#include <stdexcept>
header file.
int Mystack::pop()
{
if (isEmpty())
{
throw std::range_error("nothing to pop");
}
std::cout << "The popped element is" << A[top];
return A[top--];
}
Then you add a try/catch block to the appropriate code, perhaps with
case 4:
std::cout << "POP the element" << std::endl;
try{
s1.pop();
}
catch(const std::range_error& e)
{
std::cerr << "unable to pop!\n";
// error handling code
}
break;
Another solution, particularly appropriate when errors aren't as exceptional, such as with file I/O is more intrusive to the user code, but offers a better solution than returning an arbitrary value
int Mystack::pop(int& value)
{
if( isEmpty() )
{
return 1;
}
std::cout << "The popped element is" << A[top];
value = A[top--];
return 0
}
And then your code becomes
case 4:
std::cout << "POP the element" << std::endl;
{
int value;
if( s1.pop(value) == 1 ){
// error code
}
}
break;