2014-07-03 14 views
14

Sappiamo che la chiamata Rf_error() deve essere evitata in Rcpp in quanto implica un longjmp su distruttori C++ sullo stack. Questo è il motivo per cui preferiamo lanciare eccezioni C++ nel codice Rcpp (come throw Rcpp::exception("...") o tramite la funzione stop("...")).Come generare un avviso R in modo sicuro in Rcpp

Tuttavia, gli avvisi R possono anche comportare una chiamata a Rf_error() (questo comportamento dipende dall'opzione warn). Quindi, una chiamata allo Rf_warning() è anche rischiosa.

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 

Vediamo che il distruttore non è stato chiamato (non c'è un messaggio di "fine").

Come generare un avviso R in un C++ - modo distruttore-friendly?

risposta

10

Una delle soluzioni che mi è venuta coinvolge chiamando la funzione warning della R da Rcpp:

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

che dà il comportamento corretto se warn>2:

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

Mi chiedo se qualcuno ha una migliore idea per quello.

+5

Penso che questo dovrebbe andare bene, basta fare attenzione agli oggetti statici. –

6

mi consiglia di utilizzare stop() (che è un wrapper try/catch) invece:

con il codice leggermente modificato:

#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() 
*/ 

ottengo il comportamento desiderato:

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> 

Il È noto il problema longjmp, ma non si vince evitando i meccanismi che dobbiamo srotolare gli oggetti.

+0

OK, @DirkEddelbuettel, sono perfettamente consapevole del problema 'longjmp', ma in genere desidero generare un avviso, non un errore. Ma se 'warn> 2' voglio che fallisca in modo pulito. – gagolews

+2

Oh, scusate, quindi potrei aver frainteso la domanda. È ancora all'inizio della giornata qui a useR :) Forse abbiamo bisogno di un punto di accesso C++ in 'warning()' di R ... –

+0

Un tale punto di accesso potrebbe fare il trucco :) – gagolews

Problemi correlati