21

我们知道Rf_error()在 Rcpp 中应该避免调用,因为它涉及堆栈上 C++ 析构函数的 longjmp。这就是为什么我们宁愿在 Rcpp 代码中抛出 C++ 异常(如throw Rcpp::exception("...")或通过stop("...")函数)。

但是,R 警告也可能导致调用Rf_error()(此行为取决于warn选项)。因此,调用 toRf_warning()也是有风险的。

Rcpp::sourceCpp(code = '

   #include <Rcpp.h>
   using namespace Rcpp;

   class Test {
      public:
         Test() { Rcout << "start\\n"; }
         ~Test() { Rcout << "end\\n"; }
   };

   // [[Rcpp::export]]
   void test() {
      Test t;
      Rf_warning("test");
   }
')

options(warn=10)
test()
## start
## Error in test() : (converted from warning) test

我们看到没有调用析构函数(没有“结束”消息)。

如何以 C++ 析构函数友好的方式生成 R 警告?

4

2 回答 2

14

我想出的解决方案之一是warning从 Rcpp 调用 R 的函数:

// [[Rcpp::export]]
void test() {
   Test t;
   Function warning("warning");
   warning("test"); // here R errors are caught and transformed to C++ exceptions
}

如果warn>2

start
end
Error in eval(expr, envir, enclos) : (converted from warning) test

我想知道是否有人对此有更好的主意。

于 2014-07-03T15:30:26.090 回答
9

我建议使用stop()(这是一个包装器try/catch)代替:

稍微修改您的代码:

#include <Rcpp.h>
using namespace Rcpp;

class Test {
public:
    Test() { Rcout << "start\n"; }
    ~Test() { Rcout << "end\n"; }
};

// [[Rcpp::export]]
void test() {
    Test t;
    Rf_warning("test");
}

// [[Rcpp::export]]
void test2() {
    Test t;
    stop("test2");
}

/*** R
options(warn=10)
#test()
test2()
*/

我得到了想要的行为:

R> sourceCpp("/tmp/throw.cpp")

R> options(warn=10)

R> #test()
R> test2()
start
end
Error in eval(expr, envir, enclos) (from srcConn#3) : test2
R> 

这个longjmp问题是已知的,但你不会通过避免我们必须展开对象的机制来取胜。

于 2014-07-03T15:32:51.270 回答