Pertimbangkan 1) kelas khusus dengan cetakan memori yang berpotensi besar, dan 2) fungsi tingkat atas yang melakukan beberapa pra-pemrosesan, kemudian buat dan kembalikan objek baru dari kelas khusus kami. Untuk menghindari penyalinan yang tidak perlu dengan nilai, fungsi mengalokasikan objek dan mengembalikan pointer ke sana.
Berdasarkan diskusi sebelumnya , tampaknya cara yang tepat untuk mengembalikan pointer ke objek yang baru dibuat adalah dengan membungkusnya Rcpp::XPtr<>
. Namun, R kemudian melihatnya secara efektif externalptr
, dan saya berjuang untuk menemukan cara yang tepat untuk melemparkannya dengan cara modern RCPP_EXPOSED_CLASS
dan RCPP_MODULE
melakukan sesuatu.
Alternatifnya adalah mengembalikan pointer mentah. Tapi kemudian saya tidak 100% yakin bahwa memori objek dibersihkan dengan benar. Saya berlari valgrind
untuk menguji kebocoran memori, dan tidak menemukan apa pun. Namun, siapa yang membersihkan? 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")
;
}
Dalam 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
Pertanyaan saya adalah apakah Rcpp::Xptr<>
cara yang tepat untuk mengembalikan pointer, dan jika demikian, bagaimana saya membuat R untuk melihat hasilnya Double
, bukan externalptr
? Atau, jika mengembalikan pointer mentah tidak menyebabkan masalah memori, siapa yang membersihkan objek yang dibuat fungsi?
Rcpp::XPtr
membuat pointer eksternal dari kode C ++. Dan Anda ingin melakukan itudouble *
atau apa pun muatan Anda. Seharusnya ada contoh di sini, di Galeri, di GitHub ... Mungkin dengan pencarian termotivasi Anda dapat menemukan sesuatu yang cukup dekat?CustomClass*
. Aplikasi sebenarnya adalah struktur data khusus tanpa R yang setara dan semua interaksi dilakukan melalui fungsionalitas yang diekspos olehRCPP_MODULE
. Kecocokan terdekat dengan pencarian termotivasi yang saya temukan adalah pos dari 7 tahun yang lalu , di mana sepertinya saya perlu mendefinisikantemplate <> CustomClass* as()
konverter. Namun, saya tidak jelas bagaimana harus berinteraksi denganRCPP_MODULE
danRCPP_EXPOSED_CLASS
, terutama karena saya pikir yang terakhir sudah didefinisikanwrap()
danas()
.RCPP_EXPOSED_CLASS
danRCPP_MODULE
benar-benar cara untuk melakukannya? Saya belum pernah menggunakan atau melihat itu sebelumnya.Jawaban:
Saya pikir masuk akal untuk melihat pendekatan yang berbeda secara terpisah. Ini membuat perbedaan menjadi lebih jelas. Perhatikan bahwa ini sangat mirip dengan diskusi dalam sketsa Modul Rcpp.
Saat menggunakan
Rcpp::XPtr
Anda memiliki kelas dan menyediakan fungsi C ++ yang diekspor untuk setiap metode yang ingin Anda paparkan:Keluaran:
Perhatikan bahwa dalam R objek hanya "penunjuk". Anda bisa menambahkan kelas S4 / RC / R6 / ... di sisi R jika Anda menginginkan sesuatu yang lebih bagus.
Membungkus pointer eksternal ke dalam kelas di sisi R adalah sesuatu yang Anda dapatkan secara gratis dengan menggunakan modul Rcpp:
Keluaran:
Itu juga didukung untuk menggunakan metode pabrik bukan konstruktor di C ++ tetapi dengan penggunaan yang identik di sisi R:
Keluaran:
Akhirnya,
RCPP_EXPOSED_CLASS
berguna jika Anda ingin menggabungkan fungsi pabrik sisi R dengan Modul Rcpp, karena ini menciptakanRcpp::as
danRcpp::wrap
ekstensi yang diperlukan untuk meneruskan objek maju mundur antara R dan C ++. Pabrik dapat diekspor melaluifunction
seperti yang Anda lakukan atau menggunakan Atribut Rcpp, yang menurut saya lebih alami:Keluaran:
Mengenai pembersihan:
Rcpp::XPtr
Modul Baik dan Rcpp mendaftarkan finalizer default yang memanggil destruktor objek. Anda juga dapat menambahkan finalizer khusus jika diperlukan.Saya merasa sulit untuk memberikan rekomendasi untuk salah satu pendekatan ini. Mungkin yang terbaik adalah mencoba masing-masing pada beberapa contoh sederhana dan melihat apa yang menurut Anda lebih alami untuk digunakan.
sumber
factory
adalah bagian konektor kunci saya telah hilang.function
juga mendaftar finalizer, atau hanya itufactory
?class_<T>
dan tidak tergantung pada bagaimana objek dibuat.