I'm going to start this new project in C++ and am thinking about an un-painful way to do error handling. Now, I'm not going to start out throwing and catching exceptions, and will quite possibly never throw exceptions at all, but I was thinking - even for regular error handling, why roll my own / copy-paste a class for describing errors/status, when I could just use std::exception
and its child classes (Or perhaps an std::optional<std::exception>
)?
using Status = std::optional<std::exception>;
Status somethingThatMayFail(int x);
Is anybody/any project working this way? Is it a ridiculous idea or just a bit creaky?
The try block lets you test a block of code for errors. The except block lets you handle the error. The else block lets you execute code when there is no error. The finally block lets you execute code, regardless of the result of the try- and except blocks.
ferror() function is contained in stdio. This function basically checks for error in the file stream. It returns zero value if there is no error or else, it returns a positive non-zero value in case of error. File pointer stream is passed as an argument to the function.
All exception and error types are subclasses of class Throwable, which is the base class of the hierarchy.
I don't think you should construct exceptions unless you actually intend to throw them. I would recommend a bool or enum return type. The intent will be much clearer to someone reading your code, and they will be faster. However, if you construct an exception, someone else will come along and think they can throw the exception and cause the whole system to crash.
C++ exceptions play an important role in resource management, triggering destructors and all that (RAII). Using them any other way is going to hurt performance and (more importantly) confuse the holy heck out of anyone trying to maintain the code, later.
You can, however, do what you want with a status reporting class that does NOT have anything to do with std::exception. People do way too much for "faster" code when they don't need to. If a status enum isn't good enough, and you need to return more info, then a status reporting class will work. If it makes the code easier to read, then go for it.
Just don't call it an exception unless you actually throw it.
I think that performance alone might prove problematic. Consider the following code:
#include <iostream>
#include <chrono>
#include <ctime>
#include <stdexcept>
#include <boost/optional.hpp>
int return_code_foo(int i)
{
if(i < 10)
return -1;
return 0;
}
std::logic_error return_exception_foo(int i)
{
if(i < 10)
return std::logic_error("error");
return std::logic_error("");
}
boost::optional<std::logic_error> return_optional_foo(int i)
{
if(i < 10)
return boost::optional<std::logic_error>(std::logic_error("error"));
return boost::optional<std::logic_error>();
}
void exception_foo(int i)
{
if(i < 10)
throw std::logic_error("error");
}
int main()
{
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
for(size_t i = 11; i < 9999999; ++i)
return_code_foo(i);
end = std::chrono::system_clock::now();
std::cout << "code elapsed time: " << (end - start).count() << "s\n";
start = std::chrono::system_clock::now();
for(size_t i = 11; i < 9999999; ++i)
return_exception_foo(i);
end = std::chrono::system_clock::now();
std::cout << "exception elapsed time: " << (end - start).count() << "s\n";
start = std::chrono::system_clock::now();
for(size_t i = 11; i < 9999999; ++i)
return_optional_foo(i);
end = std::chrono::system_clock::now();
std::cout << "optional elapsed time: " << (end - start).count() << "s\n";
start = std::chrono::system_clock::now();
for(size_t i = 11; i < 9999999; ++i)
exception_foo(i);
end = std::chrono::system_clock::now();
std::cout << "exception elapsed time: " << (end - start).count() << "s\n";
return 0;
}
On my CentOS, using gcc 4.7, it timed at:
[amit@amit tmp]$ ./a.out
code elapsed time: 39893s
exception elapsed time: 466762s
optional elapsed time: 215282s
exception elapsed time: 38436s
in vanilla settings, and:
[amit@amit tmp]$ ./a.out
code elapsed time: 0s
exception elapsed time: 238985s
optional elapsed time: 33595s
exception elapsed time: 24350
at -O2 settings.
P.S. I personally would use exceptions/stack-unwinding due to a belief that it is a fundamental part of C+, possibly as @vsoftco said above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With