2014-07-03 8 views
14

Wir wissen, dass Aufruf in Rcpp Rf_error() vermieden werden sollte, da es eine longjmp über C++ - Destruktoren auf dem Stapel enthält. Deshalb werfen wir C++ - Exceptions lieber in Rcpp-Code (wie throw Rcpp::exception("...") oder über die stop("...")-Funktion).So generieren Sie eine R-Warnung sicher in Rcpp

R-Warnungen können jedoch auch zu einem Aufruf von Rf_error() führen (dieses Verhalten hängt von der Option warn ab). So ist ein Anruf zu Rf_warning() auch riskant.

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 

Wir sehen, dass der Destruktor aufgerufen wurde nicht (es gibt keine „Ende“ -Meldung).

Wie generiert man eine R-Warnung in einer C++ - Destruktor-freundlichen Weise?

Antwort

10

Eine der Lösungen, kam ich mit beinhaltet bis die warning Funktion von RCPP der R Aufruf:

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

, die das richtige Verhalten, wenn warn>2 gibt:

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

Ich frage mich, ob jemand eine bessere hat Idee dafür.

+5

Ich denke, das sollte in Ordnung sein - seien Sie vorsichtig mit statischen Objekten. –

6

Ich würde empfehlen, stop() mit (was ein Wrapper um try/catch ist) statt:

mit Ihrem Code leicht geändert:

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

ich das gewünschte Verhalten:

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> 

Die longjmp Problem ist bekannt, aber Sie gewinnen nicht, indem Sie die Mechanismen vermeiden, die wir Objekte abwickeln müssen.

+0

OK, @DirkEddelbuettel, mir ist das Problem 'longjmp' durchaus bekannt, aber ich möchte generell eine Warnung und keinen Fehler erzeugen. Aber wenn 'warn> 2 ', möchte ich, dass es sauber ausfällt. – gagolews

+2

Oh, Entschuldigung, dann habe ich vielleicht die Frage falsch gelesen. Es ist noch früh am Tag hier bei userR :) Vielleicht brauchen wir einen C++ Access Point in Rs 'warning()' ... –

+0

So ein Access Point könnte den Trick machen :) – gagolews

Verwandte Themen