Considérons 1) une classe personnalisée avec une impression de mémoire potentiellement volumineuse et 2) une fonction de niveau supérieur qui effectue un prétraitement, puis crée et renvoie un nouvel objet de notre classe personnalisée. Pour éviter une copie inutile par valeur, la fonction alloue l'objet et lui renvoie un pointeur à la place.
Sur la base d'une discussion précédente , il semble que la bonne façon de renvoyer un pointeur sur un objet nouvellement créé est de l'envelopper Rcpp::XPtr<>
. Cependant, R le voit alors efficacement externalptr
, et j'ai du mal à trouver la bonne façon de le mouler avec la manière moderne RCPP_EXPOSED_CLASS
et la RCPP_MODULE
façon de faire les choses.
L'alternative est de renvoyer le pointeur brut. Mais je ne suis pas sûr à 100% que la mémoire de l'objet soit correctement nettoyée. J'ai couru valgrind
pour tester les fuites de mémoire et il n'en a pas trouvé. Mais qui fait le nettoyage? 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")
;
}
Dans 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
Ma question est de savoir si Rcpp::Xptr<>
est la bonne façon de renvoyer des pointeurs, et si oui, comment puis-je obtenir R pour voir le résultat Double
, non externalptr
? Alternativement, si le retour d'un pointeur brut ne cause pas de problèmes de mémoire, qui nettoie l'objet créé par la fonction?
CustomClass*
. L'application réelle est une structure de données personnalisée sans équivalent R et toutes les interactions se font via la fonctionnalité exposée par le RCPP_MODULE
. La correspondance la plus proche que ma recherche motivée a trouvée était un article d'il y a 7 ans , où il semble que je doive définir un template <> CustomClass* as()
convertisseur. Cependant, je ne sais pas comment il devrait interagir avec RCPP_MODULE
et RCPP_EXPOSED_CLASS
, d'autant plus que je pensais que ce dernier était déjà défini wrap()
et as()
.
RCPP_EXPOSED_CLASS
et RCPP_MODULE
est-ce vraiment le moyen de le faire? Je n'ai jamais utilisé ou vu cela auparavant.
Rcpp::XPtr
créer un pointeur externe à partir du code C ++. Et vous voulez le faire fairedouble *
ou quelle que soit votre charge utile. Il devrait y avoir des exemples ici, à la galerie, au GitHub ... Peut-être qu'avec une recherche motivée, vous pouvez trouver quelque chose d'assez proche?