I am using the following C++ code from the boost library :
try{
child c(commandString, (std_out & std_err) > pipe_stream);
} catch(process_error &pe){
cout<<pe.what()<<" second line"<<endl;
}
The commandString is a command like ls or any other command. But if a command that does not exist is typed as per the documentation it throws the process_error exception.
I am catching the exception here but not sure if there is a better way to print out the details of the exception or error than pe.what() above?
If you look at the boost reference about boost::process::process_error, you can read this:
struct process_error : public system_error {
};
It merely inherits std::system_error but can then be distinguished in the catch-block from other system errors.
emphasis mine
If you look then at the std::system_error reference, like all other standard exceptions, what() is the way to provide detailed information about the raised error so I would say yes, this is the proper way to print out the exception details.
But since boost::process::process_error does not override the what() function, it would return the same as a std::system_error would.
An alternative interface is using std::error_code.
There are pros and cons:
PRO: it enables you to get more detail about where an error condition arose. (This is a hypothetical difference because it's not specified whether what() may include info beyond an error condition)
CON: it might not get as much detail as in the exception message
CON: since some errors are exceptional, it's harder to express the possible error conditions in the interface: the error conditions get in the way in a way that exceptions do not
in your code you might have created this problem by handling exceptions: now how do decide what value(s) to return
NEUTRAL: you may still have to handle exceptions because exceptions can arise from any related code (e.g. during setup, doing allocations).
NEUTRAL: the code() member of boost::process::process_error is likely to be 100% identical to the error_code that you get
Demo
Contrast the implementations and output below:
Live On Coliru
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int using_exceptions(std::string const& commandString) {
try {
bp::pstream pipe_stream;
bp::child c(commandString, (bp::std_out & bp::std_err) > pipe_stream);
c.wait();
return c.exit_code();
} catch (std::exception const& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return -1; // WHAT TO RETURN
}
}
int using_error_code(std::string const& commandString) {
try {
bp::pstream pipe_stream;
std::error_code ec;
bp::child c(commandString, (bp::std_out & bp::std_err) > pipe_stream,
ec);
if (ec) {
std::cerr << "Cannot spawn child process: " << ec.message() << "\n";
return -1; // WHAT TO RETURN?
} else {
c.wait(ec);
std::cerr << "Error: " << ec.message() << "\n";
return c.exit_code();
}
} catch (std::exception const& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return -1; // WHAT TO RETURN
}
}
int main()
{
auto cmd = "/usr/bin/bogus";
std::cout << "Using error_code: " << using_error_code(cmd) << "\n";
std::cout << "Using exceptions: " << using_exceptions(cmd) << "\n";
}
Prints
Using error_code: Cannot spawn child process: No such file or directory
-1
Using exceptions: Exception: execve failed: No such file or directory
-1
Related
<C++>In exception handling, do you need to know what exception and where an exception is going to occur? Can you make a code which will print and notify us that an exception occurred somewhere in the program. I mean I have a program in which I don't know if an exception will occur or not, if one was to occur, then it will print to notify us.
Exception handling is something you should design for, and in fact it works very well together with RAII (https://en.cppreference.com/w/cpp/language/raii).
(Notr On embedded platforms using exceptions, is not so popular because of some runtime overhead). What I personally like about exceptions is that it separates error handling from the normal program flow (there will be hardly any if then else checks when done right)
// Exception handling should be part of your overal design.And many standard library functions can throw exceptions, It is always up to you where you handle them.
#include <iostream>
#include <string>
#include <stdexcept>
int get_int_with_local_exception_handling()
{
do
{
try
{
std::cout << "Input an integer (local exception handling, enter a text for exception): ";
std::string input;
std::cin >> input;
// stoi is a function that can throw exceptions
// look at the documentation https://en.cppreference.com/w/cpp/string/basic_string/stol
// and look for exceptions.
//
int value = std::stoi(input);
// if input was ok, no exception was thrown so we can return the value to the client.
return value;
}
// catch by const reference, it avoids copies of the exception
// and makes sure you cannot change the content
catch (const std::invalid_argument& e)
{
// std::exceptions always have a what function with readable info
std::cout << "handling std::invalid_argument, " << e.what() << "\n";
}
catch (const std::out_of_range& e)
{
std::cout << "handling std::out_of_range, " << e.what() << "\n";
}
} while (true);
}
int get_int_no_exception_handling()
{
std::cout << "Input an integer (without exception handling, enter a text for exception): ";
std::string input;
std::cin >> input;
int value = std::stoi(input);
return value;
}
int main()
{
try
{
// this function shows you can handle exceptions locally
// to keep program running
auto value1 = get_int_with_local_exception_handling();
std::cout << "your for input was : " << value1 << "\n";
// this function shows that exceptions can be thrown without
// catching, but then the end up on the next exception handler
// on the stack, which in this case is the one in main
auto value2 = get_int_no_exception_handling();
std::cout << "your input was : " << value1 << "\n";
return 0;
}
catch (const std::exception& e)
{
std::cout << "Unhandled exception caught, program terminating : " << e.what() << "\n";
return -1;
}
catch (...)
{
std::cout << "Unknown, and unhandled exception caught, program terminating\n";
}
}
Yes and no.
No, because any exception thrown via throw some_exception; can be catched via catch(...).
Yes, because catch(...) is not very useful. You only know that there was an excpetion but not more.
Typically exceptions carry information on the cause that you want to use in the catch. Only as a last resort or when you need to make abolutely sure not to miss any excpetion you should use catch(...):
try {
might_throw_unknown_exceptions();
} catch(std::exception& err) {
std::cout << "there was a runtime error: " << err.what();
} catch(...) {
std::cout << "an unknown excpetion was thrown.";
}
The C++ standard library uses inheritance only sparingly. Exceptions is only place where it is used extensively: All standard exceptions inherit from std::exception and it is good practice to inherit also custom exceptions from it.
The question is simple, yet I cannot figure out how to do it. I want to get the system_error, and from there get the concrete error code. I have something like this in the error:
Dynamic exception type: boost::exception_detail::clone_impl<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >
std::exception::what:
boost::system::system_error
I can catch a boost::exception but not std::runtime_error or a boost::system_error directly:
try {
this->service_.run();
}
catch (boost::system::system_error const & e) {
i_->playerLog->info("Exiting with system error. Error code: {} -- What: {}", e.code().value(),
e.what());
}
catch (boost::exception const & e) {
i_->playerLog->info("Exiting with boost exception: {}", boost::diagnostic_information(e));
}
My code will enter boost::exception clause, but never system_error or runtime_erro
This should be no problem:
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
int main() {
try {
using namespace boost::asio;
io_service svc;
ip::tcp::acceptor a(svc);
a.open(ip::tcp::v4());
a.bind({{}, 22}); // error, need admin privs
} catch(boost::system::system_error const& e) {
std::cout << e.what() << ": " << e.code() << " - " << e.code().message() << "\n";
}
}
Prints
bind: Permission denied: system:13 - Permission denied
If it doesn't, usually you have some kind of mix of dynamically loaded libraries with unmatching type information.
BONUS
For completeness, tested with more elaborate exception information: Live On Coliru
RapidXml throws an exception in case of an invalid XML file. Is it possible to recover from such a failure?
For example, is it possible to check if the XML is valid beforehand, or recover and continue on?
It seems that when such failures happen, there is only assert and exit of process, and no chance for recovery.
By default, RapidXML raises exceptions on parse errors; it doesn't assert (perhaps by assert you just meant the process aborts).
It is possible to configure RapidXML with your own error handler called rapidxml::parse_error_handler if you #define RAPIDXML_NO_EXCEPTIONS before including the RapidXML headers, and if such an error handler returns, RapidXML will call assert(0), but I suspect that you don't have that enabled and you just need to be catching the right exception.
There's just one exception to catch for parse errors, and it's called rapidxml::parse_error, but RapidXML will also throw std::runtime_error if it fails to find the file.
Here's an example which catches both exception types, plus some catch-all handlers:
#include <iostream>
#include "rapidxml.hpp"
#include "rapidxml_utils.hpp"
int main()
{
try
{
rapidxml::file<> xmlFile("test.xml");
rapidxml::xml_document<> doc;
doc.parse<0>(xmlFile.data());
}
catch (const std::runtime_error& e)
{
std::cerr << "Runtime error was: " << e.what() << std::endl;
}
catch (const rapidxml::parse_error& e)
{
std::cerr << "Parse error was: " << e.what() << std::endl;
}
catch (const std::exception& e)
{
std::cerr << "Error was: " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "An unknown error occurred." << std::endl;
}
}
My large application has this structure:
int main()
{
try {
...
} catch (std::exception& e) {
std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
return 1;
}
}
Deep inside the call stack, various objects check their internal state, throwing std::runtime_exception if they detect something bad. The all-inclusive exception handler catches it, prints some moderately useful info and terminates the program.
However, when I am debugging under MS Visual Studio, I could benefit from not having any exception handler: Visual Studio has its own, very useful, handler, which stops my application at the place where the exception is thrown, so I can examine what went wrong.
How can I do the catching of my exceptions conditionally?
I tried the following:
try {
...
} catch (std::exception& e) {
if (IsDebuggerPresent())
throw;
else
std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
}
This gave a weird result: Visual Studio caught the exception that was rethrown and showed me the stack trace at the point where the exception was thrown. However, all objects in my application were apparently destructed, and I couldn't see e.g. local or member variables.
I could make the exception handler conditional on a compilation flag:
#ifdef NDEBUG
try {
#endif
...
#ifdef NDEBUG
} catch (std::exception& e) {
std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
}
#endif
but this is inconvenient because I have to recompile everything if I want to debug it.
So, how can I make my exception handling conditional (depending on a command-line argument, for example)?
So, how can I make my exception handling conditional (depending on a command-line argument, for example)?
By writing the code for it :o]
Consider this original code:
int main()
{
try {
run_the_application(); // this part different than your example
} catch (std::exception& e) {
std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
return 1;
}
}
New code:
template<typename F>
int fast_run(F functor) { functor(); return EXIT_SUCCESS; }
template<typename F>
int safe_run(F functor)
{
try {
functor();
} catch (std::exception& e) {
std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
template<typename F>
int run(const std::vector<std::string>& args, F functor)
{
using namespace std;
if(end(args) != find(begin(args), end(args), "/d"))
return fast_run(functor);
else
return safe_run(functor);
}
int main(int argc, char** argv)
{
const std::vector<std::string> args{ argv, argv + argc };
return run(args, run_the_application);
}
As suggested by CompuChip, Visual Studio can break execution when throwing an exception, not only when catching an uncaught one!
To enable this (in Visual Studio 2012):
In the menu, go Debug -> Exceptions
In the opened window, tick the "Thrown" box for all C++ exceptions (ticking just std::exception is not enough - I don't know why)
Run your program
This is something far from great but you can define command line parameter in CMake (assuming you use it):
-DCATCH_ALL=true
Then, in CMakelists.txt, you can propagate this to C++ macro:
if (CATCH_ALL)
message("Some exceptions with not be caught")
add_compile_definitions(CATCH_ALL)
else ()
message("Trying to catch more exceptions to provide better diagnostics")
endif ()
And finally, in the code:
#ifdef CATCH_ALL
try {
#endif
a = big_problematic_algorithm(problematic_parameter);
#ifdef CATCH_ALL
} catch (const std::exception &err) {
LOGF(WARN, "Crashed for the parameter %s: %s", problematic_parameter.c_str(), err.what());
}
#endif
It is rather clumsy but OK if not used too often, only somewhere at very high level (handling a complete web request, user action, file to process or the like). It allows to provide better diagnostic logs if the crash happens not while running in IDE, also to recover if you throw this exception yourself so know how.
It is possible to configure IDE to set the CMake parameter. When building on the integration server or from the command line, this is just not done activating additional handling of exceptions.
I would like to add information on what the program was about to do to my
exception handling. The old code had one big try-block around everything:
try {
read_cfg(); // a sub call might throw runtime_error
operation1();
operation2();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
// FIXME: also show what we were trying to do
// FIXME: and what a user could try
<< "\n";
}
Example error message:
Error: file "foo.cfg" not found, while reading configuration.
Please make sure the file exists.
I converted the try-block into three blocks, but this feels odd:
try {
read_cfg(); // a sub call might throw runtime_error
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while reading configuration."
<< "\n";
}
try {
operation1();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while performing operation 1."
<< "\n";
}
try {
operation2();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while performing operation 2."
<< "\n";
}
I also tried to introduce one exception class per call (read_cfg_exception,
operation1_exception, operation2_exception). Since in read_cfg() the call to
open might throw, I catch its exception and convert it to a
read_cfg_exception, thereby saving the additional information, that something
whent wrong "while reading configuration". Yet this does not feel right either:
class read_cfg_exception;
void open(std::string name); // might throw std::runtime_error
void read_cfg()
{
try {
open("foo.cfg");
}
catch (std::runtime_error& e) {
throw read_cfg_exception(e.what() + "while reading configuration");
}
}
Therefor I have the question: What is a good pattern to show the additional
information of what the program was doing while the error occured.
take a look at POCO (c++ library) throwing system, that should answer all your questions, you'll learn a lot from that and many good style rules too. The answare to your question will be really long unfortunately (at least I don't know how to make it short).
Anyway don't implement something that makes your code not readable, in your example code is not readable and then not maintainable wich is not wanted.