/
2013-01-13-intro-to-exceptions.cpp
124 lines (103 loc) · 3.35 KB
/
2013-01-13-intro-to-exceptions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
/**
* @title Introduction to exception handling
* @author Dirk Eddelbuettel
* @license GPL (>= 2)
* @tags basics
* @summary This post illustrates how exception can be use to report error conditons.
*
* 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 <em>truly large</em> programs (and eg the
* [Google in-house C++ style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Exceptions)
* is a well-known example of the <em>Just say no</em> 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 <strong>must</strong> surround code which could <em>throw an exception</em>
* by a block of <code>try</code> and <code>catch</code>.
*
* A simple example will help.
*/
#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
}
/**
* We can look at this example with a valid, and an invalid argument:
*/
/*** R
# works
takeLog(exp(1))
# throws exception
tryCatch(takeLog(-1.0),
error = print)
*/
/**
* As we can see, execptions works as expected. By throwing an
* exception derived from the standard exception call, we arrive in
* the case first <code>catch</code> branch where the exception text
* can be captured and turned into a standard R error message.
*
* The <em>scaffolding</em> of the <code>try</code> and
* <code>catch</code> is even automatically added by our common tools
* <code>cxxfunction()</code> (from the inline package) and
* <code>sourceCpp()</code>. So this shorter function is equivalent
* <em>when these tools are used</em>. Otherwise the macros
* <code>BEGIN_CPP</code> and <code>END_CPP</code> can be used.
*/
#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);
}
/**
* Again, we can look at this example with a valid, and an invalid argument:
*/
/*** R
# works
takeLog2(exp(1))
# throws exception
tryCatch(takeLog2(-1.0),
error = print)
*/
/**
* 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 <code>stop</code>:
*/
#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);
}
/*** R
# works
takeLog3(exp(1))
# throws exception
tryCatch(takeLog3(-1.0),
error = print)
*/