I'm using sqlite3pp to manipulate database. When I tried to insert one record twice in the same table by running,
sqlite3pp::command cmd(db, "INSERT INTO Groups (Name) VALUES (?)");
cmd.binder() << "Group_one";
cmd.execute();
it throwed an excpetion and showed me this:
libc++abi.dylib: terminating with uncaught exception of type
sqlite3pp::database_error: UNIQUE constraint failed: Groups.Name
But I'm not sure what type of exception should I use to catch? I tried
try {
cmd.execute();
} catch (std::exception& ex) {}
or
try {
cmd.execute();
} catch (sqlite3pp::database_error& ex) {}
or
try {
cmd.execute();
} catch (...) {}
But none of them work. Can anyone help me here? Thanks!
Here is my code:
#include <iostream>
#include "sqlite3pp.h"
int main(int argc, const char * argv[]) {
sqlite3pp::database db("./test.db");
// Create table
db.execute("CREATE TABLE IF NOT EXISTS Groups(" \
"Name TEXT PRIMARY KEY)");
sqlite3pp::command cmd(db, "INSERT INTO Groups (Name) VALUES (?)");
cmd.binder() << "Group_one";
try {
cmd.execute(); // When I run this code twice, the exception is thrown because of UNIQUE constraint.
} catch (std::exception& ex) {
std::cout << "exception: " << ex.what() << std::endl;
}
std::cout << "Done" << std::endl;
return 0;
}
I'm the writer of sqlite3pp and sorry for confusing you.
When I wrote this, I tried to make it very light weight. So, I decided not to translate all the sqlite3 error codes into c++ exceptions.
So, as a result, the methods have the integer type return value, which is the exact same error code that sqlite3 methods return. So, in this case, you need to check the return value of execute().
But, in some places, it cannot return the error code. e.g. in ctor and dtor. For these places, I introduced the database_error exception.
I would try to catch the exception type of the message ...
catch (sqlite3pp::database_error& ex)
{
...
}
I've look into the code and in the tests the developers use code like this:
#include "sqlite3pp.h"
try
{
sqlite3pp::command cmd(...);
cmd.execute();
}
catch (exception& ex) { // Note they use a reference here "exception&"
cout << ex.what() << endl;
}
so, you should use the same, if that doesn't work either, try to catch all using:
try {
cmd.execute();
} catch (...) {} // Using the ... should fix the error, but I recomend you to find the correct exception you have to catch.
Looking at the code closer
I have found the class (in sqlite3pp.h):
class database_error : public std::runtime_error
{
public:
explicit database_error(char const* msg);
explicit database_error(database& db);
};
So you should solve the problem using:
try {
cmd.execute();
} catch (database_error &e) {}
I was having this same issue - could not catch the exception no matter what I tried. However, after some digging I found out that C++11 declares destructors to be noexcept by default. I am using C++11 and was able to "fix" the issue by making the following change to the sqlite3pp code:
~transaction() noexcept(false);
transaction::~transaction() noexcept(false)
So, perhaps this is the issue the OP had?
Related
I try to use boost exceptions and fall.
There are the problem code:
struct exception_base : virtual std::exception, virtual boost::exception
{
exception_base(std::exception&& e)
: std::exception(e)
{}
};
int main()
{
std::string exception_description;
try
{
BOOST_THROW_EXCEPTION(exception_base(std::runtime_error("hello exception")));
}
catch (exception_base& ex)
{
exception_description = boost::diagnostic_information(ex);
}
return 0;
}
In this case the value of the exception_description have the last string - "std::exception::what: Unknown exception". It is unexpected value. If I change BOOST_THROW_EXCEPTION to usual throw - the last string of exception_description value looks expected - "std::exception::what: hello exception"
So how to use BOOST_THROW_EXCEPTION correctly?
Your custom exception class is not necessary, and is the root cause of your problems. If you remove it you can just do this:
BOOST_THROW_EXCEPTION(std::runtime_error("hello exception"));
Then:
catch (const std::exception& ex)
And the code will work the way you expect.
Why was it not working before? Well, your exception_base class has no storage for the error message, so when you construct it from a std::exception it cannot store the message (e.g. from the original runtime_error).
You could fix it a lot of different ways, but ultimately they will boil down to the same thing: if you want your custom exception class to contain a message string, it must somehow contain that message string.
I'm a fan of not defining custom exception types 95% of the time, so I'd advise you to just keep it simple and use runtime_error (and/or logic_error).
Note that BOOST_THROW_EXCEPTION automatically adds boost::exception as a base class for the thrown type, so you do not need to do that yourself anyway--there's no advantage.
other things:
at your catch site use std::cerr << boost::diagnostic_information(ex) << std::endl; and that will print all the metadata that BOOST_THROW_EXCEPTION adds on like: file, line, function, etc
if you are throwing a std::exception inside of the BOOST_THROW_EXCEPTION() you can wrap your std::exception with boost::enable_error_info() to change the type to boost::exception and that allows you to enrich the exception with other arbitrary fields via operator<<
Are there any conventions about which error numbers I should use in my C++ code?
Do I start at 1 or should I pick a high number and go from there?
An example was requested, so here it is:
#define ERR_EVERYTHING_IS_WRONG 42
try
{
throw ERR_EVERYTHING_IS_WRONG;
}
catch(int err)
{
//
}
For try-catch, do not use numbers! Use a class derived from a standard exception class. Example:
#include <stdexcept>
class my_error : public std::runtime_error {
public:
explicit my_error(const std::string& what_arg) : std::runtime_error(what_arg) {};
};
Usage (Coliru):
#include <iostream>
int main() {
try {
throw my_error("You can even pass a string here!");
} catch (const my_error& e) {
std::cerr << e.what();
}
}
Or simpler: use std::runtime_error
#include <stdexcept>
#include <iostream>
int main() {
try {
throw std::runtime_error("Error happened");
} catch (const std::runtime_error& e) {
std::cerr << e.what();
}
}
Without standard library:
class my_error {
};
int main() {
try {
throw my_error();
} catch (const my_error& e) {
//TODO handle my_error
}
}
One of the best way is to follow standard for conventions of different errors in C++ codes is Enum
eg:
enum FILE_ERROR{
FILE_NOT_FOUND,
FILE_NO_ACCESS,
FILE_BUSY
};
so in code u can use FILE_NOT_FOUND as error number which is 0 . So this makes easy to understand what error type stands for what
There is no rule, you can do whatever you want as long as you keep a logical way to assign it.
If you choose 3 for bad user input, keep it for only that error or you'll get lost really soon
In C++ it is common to have 1 as success and 0 as error code, unlikely to C, where there are many functions returning 0 as success (strcmp, etc...)
this may be confusing sometimes, especially when interacting with C code, however I find that it helps a lot readability.
if(cplusplus_function()) {...}
is a lot more readable than
if(!c_function()){ ... }
remember also that you have exceptions to leverage in C++, and try to avoid nesting if-s
You don't "throw" any number, you "throw" an exception, an object of a class that derives from std::exception.
Standard exceptions contain text, and do not actually contain an error number. You can however create different classes for different types of exceptions, and have different catch handlers dependent on which exception type was thrown.
I've written a function that uses Armadillo svd_econ function. I'm trying to handle the case where the svd fails to converge, because for some reason it doesn't abort the function in that case.
The error in question reads:
error: svd_econ(): failed to converge
Based on my reading of the SVD documentation, this should throw a std::runtime_error, and based on my reading of the Exceptions tutorial, I should be able to handle it like so:
arma::mat U, V;
arma::vec S;
try {
// aDat and subsetRows are previously defined
arma::svd_econ(U, S, V, aDat.rows(subsetRows), "right", "dc");
} catch (std::runtime_error e) {
std::cout << "Exception caught!" << std::endl;
// I want to abort, and return the error to R:
throw Rcpp::exception(e.what());
}
However, when I run this code with a case that gives me the error message above, I get a segfault. If I remove the try-catch block, the code keeps going, and throws an error further down when the code tries to use the results of the SVD.
I assume I'm just missing something obvious since I haven't formally learnt any C++
Looks good, I'd just try a few things:
a reference to the exception,
just error forwarding to R, not another throw(),
a default block with Rf_error()
So maybe (untested)
try {
arma::svd_econ(U, S, V, aDat.rows(subsetRows), "right", "dc");
} catch (std::runtime_error & e) {
std::cout << "Exception caught!" << std::endl;
forward_exception_to_r(e);
} default(...) {
Rf_error("Unknown exception");
}
but in essence you get all this for free via Rcpp Attributes as this is what the (automatically inserted) END_RCPP macro does --- see Section 2.7 of the Rcpp book for more details.
Edit But #mtall, in his comment, does what we should have done first: check the Armadillo docs. So you can simply check the return value. But you may want to try the suggested try/catch as well.
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
class FileNotFound: public logic_error
{
public:
explicit FileNotFound(const string& _Message):logic_error(_Message){}
};
int main()
{
try
{
ifstream file;
file.open("NoExistingFile");
if (file.fail())
throw FileNotFound("");
}
catch(const FileNotFound &e)
{
cout << "FileNotFound" << e.what();
}
catch(const exception &e)
{
cout << e.what();
}
return 0;
}
Output: FileNotFound
Is it Clean code (Robert Martin)?
std::exception not provide "location of an error".
Clean Code A Handbook of Agile Software Craftsmanship (Robert Martin) -> Chapter 7: Error Handling -> Provide Context with Exceptions
Considering the quoted paragraph, it is certainly not clean, because you just get the information of what happened, but you do not get the information from where the exception was thrown, therefore you can not trace it back for debugging.
Instead of using standard exceptions, I would advise to use boost exceptions, since they can provide the context from where the exception is thrown.
The more fundamental question is: Why use an exception in the first place? If it's a non-exceptional behavior (if it can be expected that a file might not be present), than no exception should be thrown at all. Instead control should flow along an "official path".
Add-on: It is not clean in the sense of the quoted book section (because the context needed to locate the problem is not provided with the exception -as others have mentioned) but also because:
The custom exception is used to manipulate control flow.
So instead of :
throw FileNotFound("");
}
catch(const FileNotFound &e)
{
Do only:
cout << "FileNotFound" << e.what();
The variable name 'e' is not really self explanatory and should also not be repeated.
The exception class should have its own file.
You should not use error and exception interchangably (in your question). This is an extra tipp imho.
I have some trouble handling custom C++ exceptions when calling from Cython.
My situation is the following: I have a library that uses CustomLibraryException for all exceptions. What I want is basically get the error message and raise a Python error with it.
The user guide has some hints but it is a bit unspecific.
The first possibility is to do:
cdef int bar() except +ValueError
This converts the CustomLibraryException to a ValueError, but loses the error message.
The other possibility is to explicitly convert the error using
cdef int raise_py_error()
cdef int something_dangerous() except +raise_py_error
I don't really understant this solution. I understood that raise_py_error has to be a C++ function that somehow handles the error. I am not sure how to handle it though. The function doesn't get an argument and is called inside the catch block in C++.
If any one has an working example of handling a C++ exception in Cython, that would be of great help.
Agreed the wording in the doc page leaves something to be desired. While "Cython cannot throw C++ exceptions", here is a raise_py_error that does what we want.
First, define the custom exception class in cython and make a handle to it using the "public" keyword
from cpython.ref cimport PyObject
class JMapError(RuntimeError):
pass
cdef public PyObject* jmaperror = <PyObject*>JMapError
Then write the exception handler (the docs aren't super clear this must be written in C++ and imported):
#include "Python.h"
#include "jmap/cy_utils.H"
#include "jmap/errors.H"
#include <exception>
#include <string>
using namespace std;
extern PyObject *jmaperror;
void raise_py_error()
{
try {
throw;
} catch (JMapError& e) {
string msg = ::to_string(e.code()) +" "+ e.what();
PyErr_SetString(jmaperror, msg.c_str());
} catch (const std::exception& e) {
PyErr_SetString(PyExc_RuntimeError, e.what() );
}
}
Finally, bring the handler into cython with an extern block, and use it:
cdef extern from "jmap/cy_utils.H":
cdef void raise_py_error()
void _connect "connect"() except +raise_py_error
Done. I now see new exception, constructed with the error code as intended:
JMapError: 520 timed connect failed: Connection refused
The default C++ exception handler in Cython should illustrate exactly how to accomplish what you are trying to do:
static void __Pyx_CppExn2PyErr() {
// Catch a handful of different errors here and turn them into the
// equivalent Python errors.
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
} catch (const std::bad_alloc& exn) {
PyErr_SetString(PyExc_MemoryError, exn.what());
} catch (const std::bad_cast& exn) {
PyErr_SetString(PyExc_TypeError, exn.what());
} catch (const std::domain_error& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::invalid_argument& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::ios_base::failure& exn) {
// Unfortunately, in standard C++ we have no way of distinguishing EOF
// from other errors here; be careful with the exception mask
PyErr_SetString(PyExc_IOError, exn.what());
} catch (const std::out_of_range& exn) {
// Change out_of_range to IndexError
PyErr_SetString(PyExc_IndexError, exn.what());
} catch (const std::overflow_error& exn) {
PyErr_SetString(PyExc_OverflowError, exn.what());
} catch (const std::range_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
} catch (const std::underflow_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
} catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
So you can either #define __Pyx_CppExn2PyErr your_custom_exn_handler in an included .h file to override the generic behavior, or use a one-off custom handler as
cdef extern from "...":
void your_exn_throwing_fcn() except +your_custom_exn_handler
If CustomLibraryException derives from std::runtime_error (as a well-behaved C++ exception should), then the behavior you're seeing is a bug in Cython.
If it doesn't, then the easiest thing to do is to wrap the C++ function you're calling in a C++ helper function that translates the exception:
double foo(char const *, Bla const &); // this is the one we're wrapping
double foo_that_throws_runtime_error(char const *str, Bla const &blaref)
{
try {
return foo(str, blaref);
} catch (CustomLibraryException const &e) {
throw std::runtime_error(e.get_the_message());
}
}
This will cause a RuntimeError to be raised on the Python side. Alternatively, throw an std::invalid_argument to raise a ValueError, etc. (see the table in the page you linked to).
In Cython's sources, https://github.com/cython/cython/blob/master/tests/run/cpp_exceptions.pyx they actually implement the raise_py_error in a .pyx file. This makes it a lot easier to share error handling between other .pyx files.
A quick solution involves simply 2 files : myerror.pyx :
class MyError(RuntimeError):
"Base class for errors raised from my C++."
pass
cdef int raise_my_py_error() except *:
raise MyError("There was a problem")
and myerror.pxd :
cdef int raise_my_py_error() except *
which allows you to add an except +my_py_error in all your files.
However, this "loses" the e.what() of C++ exceptions. So a more interesting solution needs a couple more helper files :
my_error_helper.h :
extern const char* get_my_py_error_message();
my_error_helper.cxx :
#include <exception>
const char* get_my_py_error_message()
{
try {
throw;
} catch (const my_custom_cxx_exception& e) {
return e.what();
}
}
my_error_helper.pxd :
cdef extern from "my_error_helper.h":
const char* get_my_py_error_message()
my_error.pxd :
cdef int raise_my_py_error() except *
my_error.pyx :
cimport my_error_helper
class MyError(RuntimeError):
"Base class for errors raised from my C++."
pass
cdef int raise_my_py_error() except *:
msg = my_error_helper.get_my_py_error_message().decode('utf-8')
raise MyError(msg)