Skip to content

Latest commit

 

History

History
169 lines (120 loc) · 3.82 KB

2013-01-13-intro-to-exceptions.md

File metadata and controls

169 lines (120 loc) · 3.82 KB
title author license tags summary layout src
Introduction to exception handling
Dirk Eddelbuettel
GPL (>= 2)
basics
This post illustrates how exception can be use to report error conditons.
post
2013-01-13-intro-to-exceptions.cpp

One of the many features that make C++ different from C is exception handling. This is a somewhat big topic, and large codebases sometimes eschew exceptions for lack of traceability in truly large programs (and eg the Google in-house C++ style guide is a well-known example of the Just say no school). Opinions are divided; exceptions are generally seen as a useful tool for smaller-scale projects.

We tend to agree. For our purposes, exceptions are just fine. They allow for a fine-grained way to report errors to R.

The basic idea is the that we must surround code which could throw an exception by a block of try and catch.

A simple example will help.

{% highlight cpp %} #include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]] double takeLog(double val) { try { if (val <= 0.0) { // log() not defined here throw std::range_error("Inadmissible value"); } return log(val); } catch(std::exception &ex) { forward_exception_to_r(ex); } catch(...) { ::Rf_error("c++ exception (unknown reason)"); } return NA_REAL; // not reached } {% endhighlight %}

We can look at this example with a valid, and an invalid argument:

{% highlight r %}

works

takeLog(exp(1)) {% endhighlight %}

[1] 1

{% highlight r %}

throws exception

tryCatch(takeLog(-1.0), error = print) {% endhighlight %}

<std::range_error: Inadmissible value>

As we can see, execptions works as expected. By throwing an exception derived from the standard exception call, we arrive in the case first catch branch where the exception text can be captured and turned into a standard R error message.

The scaffolding of the try and catch is even automatically added by our common tools cxxfunction() (from the inline package) and sourceCpp(). So this shorter function is equivalent when these tools are used. Otherwise the macros BEGIN_CPP and END_CPP can be used.

{% highlight cpp %} #include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]] double takeLog2(double val) { if (val <= 0.0) { // log() not defined here throw std::range_error("Inadmissible value"); } return log(val); } {% endhighlight %}

Again, we can look at this example with a valid, and an invalid argument:

{% highlight r %}

works

takeLog2(exp(1)) {% endhighlight %}

[1] 1

{% highlight r %}

throws exception

tryCatch(takeLog2(-1.0),
error = print) {% endhighlight %}

<std::range_error: Inadmissible value>

This shows that due to the automatic addition of the needed infrastructure, exception handling can add a useful mechanism to signal error conditions back to R.

There is even a shortcut defined as Rcpp function stop:

{% highlight cpp %} #include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]] double takeLog3(double val) { if (val <= 0.0) { // log() not defined here stop("Inadmissible value"); } return log(val); } {% endhighlight %}

{% highlight r %}

works

takeLog3(exp(1)) {% endhighlight %}

[1] 1

{% highlight r %}

throws exception

tryCatch(takeLog3(-1.0), error = print) {% endhighlight %}

<Rcpp::exception: Inadmissible value>