I am currently catching errors from boost::filesystem::is_directory and showing the error to the user by calling "what()" on the exception. This gives the reason for failure but the error is strange to the user. For example:
boost::filesystem::is_directory: Access is denied
How can I catch the boost error and figure out what the actual cause is, so I can show a nicer error message?
By "nicer error message" would you mean something like
#include <iostream>
#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path p("/proc/1/fd/1");
try {
boost::filesystem::is_directory(p);
} catch(const boost::filesystem::filesystem_error& e)
{
if(e.code() == boost::system::errc::permission_denied)
std::cout << "Search permission is denied for one of the directories "
<< "in the path prefix of " << p << "\n";
else
std::cout << "is_directory(" << p << ") failed with "
<< e.code().message() << '\n';
}
}
Related
I am writing a small application that modifies a text file. It first creates a copy of the file in case something goes wrong.
The following function creates this copy in the same directory. It takes the file's name as an argument and returns true if the copy is successfully created, and false if it fails.
#include <iostream>
#include <filesystem>
#include <fstream>
#include <string>
using std::ifstream;
using std::ofstream;
using std::string;
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
bool backupFile(string FileName) {
cout << "Creating backup for " << FileName << "..." << endl;
try { // for debugging purposes
string NewName = "bkp_" + FileName;
string CurLine;
ifstream FileCopy(FileName);
ofstream FileBackup(NewName);
if (FileCopy.fail()) { // Could specify how file copy failed?
cerr << "Error opening file " << FileName << ".";
return false;
}
while (getline(FileCopy, CurLine)) { // Copy lines to new file
//cout << "Copying " << CurLine << "\" to " << NewName << "." << endl;
FileBackup << CurLine << "\n";
}
cout << "File successfully backed up to " << NewName << endl;
return true;
}
catch (const ifstream::failure& iE) {
cerr << "Exception thrown opening original file: " << iE.what() << endl;
return false;
}
catch (const ofstream::failure& oE) {
cerr << "Exception thrown outputting copy: " << oE.what() << endl;
}
catch (...) {
cerr << "Unknown exception thrown copying file." << endl;
return false;
}
}
I've used a few catch statements to indicate if there is an issue with the input (ifstream::failure), the output (ofstream::failure), or neither.
During compilation, however, the following error appears:
error C2312: 'const std::ios_base::failure &': is caught by 'const std::ios_base::failure &' on line 42
To me, the error implies that both ifstream::failure and ofstream::failure are caught on ifstream::failure, which seems strange. When I remove the catch for ofstream::failure, it runs fine.
Why is this the case?
ifstream::failure and ofstream::failure are both the same type defined in the std::ios_base base class std::ios_base::failure, you can't catch the same type in two separate catch clauses.
Note that neither of your streams will actually throw any exceptions, by default std::fstream doesn't throw any exceptions. You have to turn exceptions on by calling exceptions:
FileCopy.exceptions(f.failbit);
FileBackup.exceptions(f.failbit);
The above will cause an std::ios_base::failure to be thrown when the stream enters the failed state. As you are already checking for FileCopy.fail() you could just expand that checking to cover other failure cases (e.g. check that FileCopy doesn't fail during getline and that FileBackup also doesn't fail) rather than enabling exceptions.
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
I have tried to create a program in C++ that can catch and handle bad_alloc exception.
While writing the code, I have noticed no errors but when I have tried to compile this code I got C2276 error code and C3876 in Microsoft Visual Studio Community 2017.
The error itself seems to appear in the catch{...} code block.
#include "pch.h"
#include <iostream>
#include <string>
using namespace std;
class CanGoWrong {
public:
CanGoWrong() {
char *pMemory = new char[9999999999];
delete[] pMemory;
}
};
int main()
{
try {
CanGoWrong wrong;
}
catch(std::bad_alloc &e){
cout << "Caught exception: "<< e.what << e << endl;
}
cout << "Still running" << endl;
return 0;
}
The error with code C3867 ("non standart syntax, use &") I fixed this way :
from
cout << "Caught exception: "<< e.what << e << endl;
to:
cout << "Caught exception: "<< &e.what << e << endl;
Still, the error C2276 won't disappear. I guess there is something to do using basic std::exception class.
I want to understand how to do it right, this code is an course sample that I must follow and understand.
I was wondering if there's a way to get an string representation of an errors type/name from std::exception. Let's say I catch std::exception &err, is there a way to say something like err.getName() or err.getType(). I have a project that can throw a wide variety of errors, but I want to get the exact type if it has not been caught by something else. I'll show what I generally mean.
For simplicity sake, let's say libraryA has several uniquely defined exception types (libraryA::Exception_# where # is replaced by a number to uniquely identify the error).
Here's some simple code for this:
try{
doSomeTaskThatMightThrowAnError();
}catch(libraryA::Exception_1 &err){
std::cout << "Error type 1: " << err.what() << std::endl;
}catch(libraryA::Exception_2 &err){
std::cout << "Error type 2: " << err.what() << std::endl;
}catch(libraryA::Exception_3 &err){
std::cout << "Error type 3: " << err.what() << std::endl;
}catch(std::exception &err){
std::cout << "Unknown error: " << err.what() << std::endl;
}
Is there some way within catch(std::exception &err)'s block that I can say std::cout << "Unknown error type: " << err.getType() << '\n' << "Error message: " << err.what() << std::endl;
I want to catch std::exception as a precaution in case nothing else catches the error, but I want to be able to identify the exact error type so I may update my code and include another catch statement for it. Is this possible?
You can always use typeid(e).name() (remember to include <typeinfo> header).
But very little is guaranteed about the name so produced.
With Visual C++ it's nice and readable, with g++ it's mangled so that you practically need to use some compiler-specific functionality to demangle it.
Could you guys help me decypher unknown exception that is thrown by boost::iostreams::mapped_file_sink ?
My configuration
boost 1.51
Visual Studio 2012 on Windows 7
GCC 4.7 on Ubuntu
Here is the code I have
try
{
boost::iostreams::mapped_file_params params_;
boost::iostreams::mapped_file_sink sink_;
params_.length = 0;
params_.new_file_size = 1024;
params_.path = "./test.bin";
sink_.open(params_);
sink_.close();
}
catch (std::ios::failure& ex)
{
std::cout << "\t" << "what: " << ex.what() << "\n";
}
catch (std::system_error& ex)
{
std::cout << "\t" << "code: " << ex.code() << " what: " << ex.what() << "\n";
}
catch (std::runtime_error& ex)
{
std::cout << "\t" << ex.what() << "\n";
}
catch (boost::archive::archive_exception& ex)
{
std::cout << "\t" << ex.what() << "\n";
}
catch (boost::exception& ex)
{
std::cout << "blah\n";
}
catch (std::exception& ex)
{
std::cout << "\t" << ex.what() << " --- " << typeid(ex).name() << "\n";
}
It always works in Windows.
In Ubuntu it creates empty file of given size but throws exception on open(). Subsequent execution of the code if exists doesn't cause exception.
The worst part is that I can't see the reason of the exception. I can only catch std::exception whose what() returns meaningless "std::exception".
In desperate attempt to find out what's wrong I output typeid(ex).name() which shows
N5boost16exception_detail10clone_implINS0_19error_info_injectorISt9exception
which according to Google means: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::exception> >
Any ideas what's wrong?
You could run the code in a debugger and set a breakpoint in the function which actually throws an exceptions, e.g., __cxa_throw. The name of the function may be different on your system: use nm -po program | less and search for a function containing throw. Set a breakpoint in the one(s) which look most likely as if they are created by the system. If there are only few exceptions being thrown, you can also set a breakpoint into std::exception::exception().
After 50 mins of guessing I found out that problem was in length field. The documentation doesn't say that but its default value has to be -1 as stated in source code
BOOST_STATIC_CONSTANT(size_type, max_length = static_cast<size_type>(-1));
I intuitively assumed that if I set new_file_size to be more than zero it would ignore length.