Considerare 1) una classe personalizzata con una memoria di memoria potenzialmente grande e 2) una funzione di livello superiore che esegue alcune preelaborazioni, quindi crea e restituisce un nuovo oggetto della nostra classe personalizzata. Per evitare copie non necessarie per valore, la funzione alloca l'oggetto e restituisce invece un puntatore ad esso.
Sulla base di una discussione precedente , sembra che il modo corretto di restituire un puntatore a un oggetto appena creato sia di avvolgerlo Rcpp::XPtr<>
. Tuttavia, R lo vede in modo efficace externalptr
, e sto lottando per trovare il modo giusto di lanciarlo con il moderno RCPP_EXPOSED_CLASS
e il RCPP_MODULE
modo di fare le cose.
L'alternativa è restituire il puntatore non elaborato. Ma poi non sono sicuro al 100% che la memoria degli oggetti venga ripulita correttamente. Ho corso valgrind
per verificare la presenza di perdite di memoria e non ne ho trovate. Tuttavia, chi pulisce? 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")
;
}
In 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
La mia domanda è se Rcpp::Xptr<>
è il modo corretto di restituire i puntatori e, in tal caso, come posso ottenere R per vedere il risultato come Double
no externalptr
? In alternativa, se la restituzione di un puntatore non elaborato non causa problemi di memoria, chi pulisce l'oggetto creato dalla funzione?
CustomClass*
. La vera applicazione è una struttura di dati personalizzata senza R equivalente e tutte le interazioni sono fatte attraverso la funzionalità esposta da RCPP_MODULE
. La corrispondenza più vicina trovata dalla mia ricerca motivata è stata un post di 7 anni fa , in cui sembra che debba definire un template <> CustomClass* as()
convertitore. Tuttavia, non sono chiaro su come dovrebbe interagire RCPP_MODULE
e RCPP_EXPOSED_CLASS
, soprattutto perché pensavo che quest'ultimo fosse già definito wrap()
e as()
.
RCPP_EXPOSED_CLASS
ed RCPP_MODULE
è davvero il modo di farlo? Non l'ho mai visto o visto prima.
Rcpp::XPtr
creare un puntatore esterno dal codice C ++. E vuoi lanciarlodouble *
o qualunque sia il tuo payload. Ci dovrebbero essere esempi qui, alla Galleria, a GitHub ... Forse con una ricerca motivata puoi trovare qualcosa di abbastanza vicino?