为多个会话保留 XPtr
Keep XPtr for multiple sessions
我有一个 R 函数,它创建一个 Primebase
Cpp Class 然后 returns 一个 XPtr<Primebase>
指针。
由于构建过程需要大量时间,我想将 Primebase
的实例保存到我的会话中,以便下次打开 R 我可以直接访问 Primebase
实例。
不幸的是,一旦我关闭 R 并且 XPtr
变成 null pointer
。
,底层对象就会被删除
有没有办法阻止 R 删除对象或任何其他方式来保存底层对象?
由 Rcpp::Xptr
管理的 C++ 对象在 R 会话结束时被销毁。如果要保存对象,则必须将其序列化。 Rcereal 包提供了一种不错的可能性。下面的例子使用一个简单的 Primebase
class 和一个构造函数中的人工睡眠来模拟构造过程中的繁重处理。检查对象的内容后,将其序列化并销毁。之后对象被反序列化并再次包装到 Xptr
中。请注意,反序列化比构造便宜得多:
#include <Rcpp.h>
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::depends(Rcereal)]]
#include <cereal/archives/binary.hpp>
#include <chrono>
#include <fstream>
#include <thread>
class Primebase
{
private:
int x;
public:
Primebase() : x{0} {};
Primebase(int x_) : x{x_} {std::this_thread::sleep_for(std::chrono::seconds(1));};
int answer() {return x;}
template <class Archive>
void serialize(Archive & ar)
{
ar(x);
}
};
// [[Rcpp::export]]
Rcpp::XPtr<Primebase> create(int x) {
Primebase* instance = new Primebase(x);
return Rcpp::XPtr<Primebase>(instance);
}
// [[Rcpp::export]]
int answer(Rcpp::XPtr<Primebase> xptr) {
return xptr.get()->answer();
}
// [[Rcpp::export]]
void mySerialize(Rcpp::XPtr<Primebase> xptr, std::string filename) {
std::ofstream os(filename, std::ios::binary);
cereal::BinaryOutputArchive archive(os);
archive(*xptr.get());
}
// [[Rcpp::export]]
Rcpp::XPtr<Primebase> myDeserialize(std::string filename) {
std::ifstream is(filename, std::ios::binary);
cereal::BinaryInputArchive archive(is);
Primebase* instance = new Primebase;
archive(*instance);
return Rcpp::XPtr<Primebase>(instance);
}
/*** R
system.time(xptr <- create(42))
answer(xptr)
mySerialize(xptr, "test.cereal")
rm(xptr)
exists("xptr")
system.time(xptr <-myDeserialize("test.cereal"))
answer(xptr)
*/
输出:
> system.time(xptr <- create(42))
user system elapsed
0.000 0.000 1.001
> answer(xptr)
[1] 42
> mySerialize(xptr, "test.cereal")
> rm(xptr)
> exists("xptr")
[1] FALSE
> system.time(xptr <-myDeserialize("test.cereal"))
user system elapsed
0 0 0
> answer(xptr)
[1] 42
参考文献:
我有一个 R 函数,它创建一个 Primebase
Cpp Class 然后 returns 一个 XPtr<Primebase>
指针。
由于构建过程需要大量时间,我想将 Primebase
的实例保存到我的会话中,以便下次打开 R 我可以直接访问 Primebase
实例。
不幸的是,一旦我关闭 R 并且 XPtr
变成 null pointer
。
有没有办法阻止 R 删除对象或任何其他方式来保存底层对象?
由 Rcpp::Xptr
管理的 C++ 对象在 R 会话结束时被销毁。如果要保存对象,则必须将其序列化。 Rcereal 包提供了一种不错的可能性。下面的例子使用一个简单的 Primebase
class 和一个构造函数中的人工睡眠来模拟构造过程中的繁重处理。检查对象的内容后,将其序列化并销毁。之后对象被反序列化并再次包装到 Xptr
中。请注意,反序列化比构造便宜得多:
#include <Rcpp.h>
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::depends(Rcereal)]]
#include <cereal/archives/binary.hpp>
#include <chrono>
#include <fstream>
#include <thread>
class Primebase
{
private:
int x;
public:
Primebase() : x{0} {};
Primebase(int x_) : x{x_} {std::this_thread::sleep_for(std::chrono::seconds(1));};
int answer() {return x;}
template <class Archive>
void serialize(Archive & ar)
{
ar(x);
}
};
// [[Rcpp::export]]
Rcpp::XPtr<Primebase> create(int x) {
Primebase* instance = new Primebase(x);
return Rcpp::XPtr<Primebase>(instance);
}
// [[Rcpp::export]]
int answer(Rcpp::XPtr<Primebase> xptr) {
return xptr.get()->answer();
}
// [[Rcpp::export]]
void mySerialize(Rcpp::XPtr<Primebase> xptr, std::string filename) {
std::ofstream os(filename, std::ios::binary);
cereal::BinaryOutputArchive archive(os);
archive(*xptr.get());
}
// [[Rcpp::export]]
Rcpp::XPtr<Primebase> myDeserialize(std::string filename) {
std::ifstream is(filename, std::ios::binary);
cereal::BinaryInputArchive archive(is);
Primebase* instance = new Primebase;
archive(*instance);
return Rcpp::XPtr<Primebase>(instance);
}
/*** R
system.time(xptr <- create(42))
answer(xptr)
mySerialize(xptr, "test.cereal")
rm(xptr)
exists("xptr")
system.time(xptr <-myDeserialize("test.cereal"))
answer(xptr)
*/
输出:
> system.time(xptr <- create(42))
user system elapsed
0.000 0.000 1.001
> answer(xptr)
[1] 42
> mySerialize(xptr, "test.cereal")
> rm(xptr)
> exists("xptr")
[1] FALSE
> system.time(xptr <-myDeserialize("test.cereal"))
user system elapsed
0 0 0
> answer(xptr)
[1] 42
参考文献: