如何正确捕获 Rcpp 异常?
How to correctly catch the Rcpp exceptions?
我创建了如下所示的函数:
#include <Rcpp.h>
//[[Rcpp::export]]
void fun(SEXP num = R_NilValue){
if(!Rf_isNull(num)){
try{
int NUM = Rcpp::as<int>(num);
}catch(...){
Rcpp::stop("Exception occured!");
}
}
}
此函数作为 R 包的一部分导出并包含在 Makevars 中。现在,如果我将一个字符串值作为参数传递给此函数 (fun("a")
),我将无法捕获异常并且 R 会话正在中止并崩溃。有什么办法可以捕获这个异常吗?
在这种情况下,我想要实现的目标是确保不将不正确的类型参数传递给函数。
如果我使用显示的调用而不是之前的调用,R 会话将中止:
// [[Rcpp::export]]
std::string fun(int imax = 214748364) {
return "okay";
}
现在,即使我的类型不匹配,调用 fun('a')
也会导致崩溃。
您的示例不完整,因为您没有告诉我们您是如何构建和调用函数的。
“一般来说”您不需要做任何事情,因为 R 会为您做。最简单的例子:
R> cppFunction("int doubleMe(int x) { return x + x; }")
R> doubleMe(21)
[1] 42
R> doubleMe("this won't work")
Error in doubleMe("this won't work") :
Not compatible with requested type: [type=character; target=integer].
R>
如果您在详细模式下使用 cppFunction
或 sourceCpp()
,您会看到生成的代码。如果您遵循该代码包括使用的#define
,您会看到它已经为您包含了一个try/catch
块这就是为什么我说你不需要做任何事情。
现在,您当然可以与 R CMD COMPILE
和朋友一起“手动”构建函数(非常)旧的方法---我 10 多年前的旧演示文稿展示了如果您需要快速阅读 - -- 并插入手动 try/catch
块来自己尝试。
简而言之,“内部”Rcpp 代码确实会抛出异常,这就是设置“外部”Rcpp 代码以捕获异常的原因。它工作得很好,并且经过多年改进以解决大多数可能在实现中具有 OS 依赖性的问题。
编辑: 这里 an old Whosebug answer of mine from 2009 展示了在 Rcpp 属性之前的日子里如何“手工”编译。它包含一个 try/catch
块,我们当时总是(手动)包含它。
编辑 2: 感谢您编辑您的问题。如果你使用 [[Rcpp::export]]
最简单的版本是
//[[Rcpp::export]]
void fun(int num) {
// do nothing
}
显示所需的行为:
R> sourceCpp("~/git/Whosebug/63049304/answer.cpp")
R> fun(2)
R> fun("lalala")
Error in fun("lalala") :
Not compatible with requested type: [type=character; target=integer].
R>
编辑 3 您在上次编辑中发布的示例甚至无法编译。
已修复,一切如常
R> cppFunction('std::string fun(int imax=1234) { return("okay"); }')
R> fun("a")
Error in fun("a") :
Not compatible with requested type: [type=character; target=integer].
R> fun('a')
Error in fun("a") :
Not compatible with requested type: [type=character; target=integer].
R>
我创建了如下所示的函数:
#include <Rcpp.h>
//[[Rcpp::export]]
void fun(SEXP num = R_NilValue){
if(!Rf_isNull(num)){
try{
int NUM = Rcpp::as<int>(num);
}catch(...){
Rcpp::stop("Exception occured!");
}
}
}
此函数作为 R 包的一部分导出并包含在 Makevars 中。现在,如果我将一个字符串值作为参数传递给此函数 (fun("a")
),我将无法捕获异常并且 R 会话正在中止并崩溃。有什么办法可以捕获这个异常吗?
在这种情况下,我想要实现的目标是确保不将不正确的类型参数传递给函数。
如果我使用显示的调用而不是之前的调用,R 会话将中止:
// [[Rcpp::export]]
std::string fun(int imax = 214748364) {
return "okay";
}
现在,即使我的类型不匹配,调用 fun('a')
也会导致崩溃。
您的示例不完整,因为您没有告诉我们您是如何构建和调用函数的。
“一般来说”您不需要做任何事情,因为 R 会为您做。最简单的例子:
R> cppFunction("int doubleMe(int x) { return x + x; }")
R> doubleMe(21)
[1] 42
R> doubleMe("this won't work")
Error in doubleMe("this won't work") :
Not compatible with requested type: [type=character; target=integer].
R>
如果您在详细模式下使用 cppFunction
或 sourceCpp()
,您会看到生成的代码。如果您遵循该代码包括使用的#define
,您会看到它已经为您包含了一个try/catch
块这就是为什么我说你不需要做任何事情。
现在,您当然可以与 R CMD COMPILE
和朋友一起“手动”构建函数(非常)旧的方法---我 10 多年前的旧演示文稿展示了如果您需要快速阅读 - -- 并插入手动 try/catch
块来自己尝试。
简而言之,“内部”Rcpp 代码确实会抛出异常,这就是设置“外部”Rcpp 代码以捕获异常的原因。它工作得很好,并且经过多年改进以解决大多数可能在实现中具有 OS 依赖性的问题。
编辑: 这里 an old Whosebug answer of mine from 2009 展示了在 Rcpp 属性之前的日子里如何“手工”编译。它包含一个 try/catch
块,我们当时总是(手动)包含它。
编辑 2: 感谢您编辑您的问题。如果你使用 [[Rcpp::export]]
最简单的版本是
//[[Rcpp::export]]
void fun(int num) {
// do nothing
}
显示所需的行为:
R> sourceCpp("~/git/Whosebug/63049304/answer.cpp")
R> fun(2)
R> fun("lalala")
Error in fun("lalala") :
Not compatible with requested type: [type=character; target=integer].
R>
编辑 3 您在上次编辑中发布的示例甚至无法编译。 已修复,一切如常
R> cppFunction('std::string fun(int imax=1234) { return("okay"); }')
R> fun("a")
Error in fun("a") :
Not compatible with requested type: [type=character; target=integer].
R> fun('a')
Error in fun("a") :
Not compatible with requested type: [type=character; target=integer].
R>