div - Cómo generar una advertencia R de forma segura en Rcpp
sidebarpanel shiny (2)
Recomendaría usar stop()
(que es un envoltorio alrededor de try/catch
) en su lugar:
Con su código ligeramente modificado:
#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()
*/
Me sale el comportamiento deseado:
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>
El problema de longjmp
es conocido, pero no gana al evitar los mecanismos que tenemos para desenrollar objetos.
Sabemos que llamar a Rf_error()
debe evitarse en Rcpp, ya que implica un longjmp sobre los destructores de C ++ en la pila. Esta es la razón por la que preferimos lanzar excepciones C ++ en el código Rcpp (como throw Rcpp::exception("...")
o mediante la función de stop("...")
).
Sin embargo, las advertencias R también pueden resultar en una llamada a Rf_error()
(este comportamiento depende de la opción de warn
). Por lo tanto, una llamada a Rf_warning()
también es arriesgada.
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
Vemos que no se ha llamado al destructor (no hay un mensaje de "fin").
¿Cómo generar una advertencia de R en una forma C ++, de una manera amigable para el destructor?
Una de las soluciones que encontré involucra llamar a la función de warning
de R desde Rcpp:
// [[Rcpp::export]]
void test() {
Test t;
Function warning("warning");
warning("test"); // here R errors are caught and transformed to C++ exceptions
}
que da el comportamiento correcto si warn>2
:
start
end
Error in eval(expr, envir, enclos) : (converted from warning) test
Me pregunto si alguien tiene una mejor idea para eso.