Keep XPtr for multiple sessions

吃可爱长大的小学妹 提交于 2019-12-22 18:25:24

问题


I have a R function that creates a Primebase Cpp Class and then returns a XPtr<Primebase> pointer.

As the construction process takes a significant amount of time I'd like to save the instance of Primebase to my session, so that the next time I open up R I can directly access the Primebase instance.

Unfortunately the underlying Object gets deleted as soon as I close R and the XPtr turns into a null pointer.

Is there a way to prevent R from deleting the object or any other way to save the underlying object?


回答1:


The C++ object that is managed by Rcpp::Xptr is destroyed when the R session ends. If you want to save the object, you have to serialize it. One nice possibility is offered by the Rcereal package. The following example uses a trivial Primebase class with an artificial sleep in one constructor to simulate heavy processing during the construction. After checking the object's content, it is serialized and destroyed. Afterwards the object is deserialized and wrapped into an Xptr again. Note that deserialization is much cheaper than construction:

#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)
*/

Output:

> 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

References:

  • Cereal documentation
  • Rcpp gallery


来源:https://stackoverflow.com/questions/53132155/keep-xptr-for-multiple-sessions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!