21

Rf_error()スタック上の C++ デストラクタ上に longjmp が含まれるため、Rcpp での呼び出しは避けるべきであることがわかっています。これが、Rcpp コードで (関数のようにthrow Rcpp::exception("...")、または関数を介してstop("...")) C++ 例外をスローする理由です。

ただし、R の警告によって が呼び出される場合もありますRf_error()(この動作はwarnオプションによって異なります)。したがって、への呼び出しRf_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

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 に答える