Considere 1) una clase personalizada con una impresión de memoria potencialmente grande, y 2) una función de nivel superior que realiza un preprocesamiento, luego crea y devuelve un nuevo objeto de nuestra clase personalizada. Para evitar una copia innecesaria por valor, la función asigna el objeto y le devuelve un puntero.
Según una discusión anterior , parece que la forma correcta de devolver un puntero a un objeto recién creado es envolverlo Rcpp::XPtr<>
. Sin embargo, R lo ve efectivamente externalptr
, y estoy luchando por encontrar la forma adecuada de lanzarlo con lo moderno RCPP_EXPOSED_CLASS
y lo moderno.RCPP_MODULE
forma de hacer las cosas.
La alternativa es devolver el puntero sin formato. Pero entonces no estoy 100% seguro de que la memoria del objeto se limpie correctamente. Corrí valgrind
a buscar pérdidas de memoria y no encontré ninguna. Sin embargo, ¿quién hace la limpieza? R?
test.cpp
#include <Rcpp.h>
// Custom class
class Double {
public:
Double( double v ) : value(v) {}
double square() {return value*value;}
private:
double value;
};
// Make the class visible
RCPP_EXPOSED_CLASS(Double)
// Option 1: returning raw pointer
Double* makeDouble( double x ) {
Double* pd = new Double(x);
return pd;
}
// Option 2: returning XPtr<>
SEXP makeDouble2( double x ) {
Double* pd = new Double(x);
Rcpp::XPtr<Double> ptr(pd);
return ptr;
}
RCPP_MODULE(double_cpp) {
using namespace Rcpp;
function( "makeDouble", &makeDouble );
function( "makeDouble2", &makeDouble2 );
class_<Double>("Double")
.constructor<double>("Wraps a double")
.method("square", &Double::square, "square of value")
;
}
En R
Rcpp::sourceCpp("test.cpp")
d1 <- makeDouble(5.4) # <-- who cleans this up???
# C++ object <0x56257d628e70> of class 'Double' <0x56257c69cf90>
d1$square()
# 29.16
d2 <- makeDouble2(2.3)
# <pointer: 0x56257d3c3cd0>
d2$square()
# Error in d2$square : object of type 'externalptr' is not subsettable
Mi pregunta es si Rcpp::Xptr<>
es la forma correcta de devolver punteros, y si es así, ¿cómo hago para que R vea el resultado Double
, no externalptr
? Alternativamente, si devolver un puntero sin formato no causa problemas de memoria, ¿quién limpia el objeto que crea la función?
CustomClass*
. La aplicación real es una estructura de datos personalizada sin equivalente de R y todas las interacciones se realizan a través de la funcionalidad expuesta por RCPP_MODULE
. La coincidencia más cercana que encontró mi búsqueda motivada fue una publicación de hace 7 años , donde parece que necesito definir un template <> CustomClass* as()
convertidor. Sin embargo, no tengo claro cómo debería interactuar RCPP_MODULE
y RCPP_EXPOSED_CLASS
, especialmente porque pensé que este último ya había definido wrap()
y as()
.
RCPP_EXPOSED_CLASS
y RCPP_MODULE
es realmente la forma de hacerlo? Nunca he usado o visto eso antes.
Rcpp::XPtr
crear un puntero externo a partir del código C ++. Y quieres lanzarlodouble *
o lo que sea tu carga útil. Debería haber ejemplos aquí, en la Galería, en GitHub ... ¿Quizás con una búsqueda motivada pueda encontrar algo lo suficientemente cerca?