创建std :: shared_ptr对象并将其返回到R端(Rcpp)

时间:2014-10-06 13:18:49

标签: c++ r rcpp

我正在尝试使用Rcpp为C ++脚本编写R绑定。其中一个函数需要std::shared_ptr object。我发现很难初始化std::shared_ptr obj并将其作为Rcpp::XPtr对象返回到R端。

我试过(最小的例子):

#include <iostream>
#include <memory>
#include <Rcpp.h> 
using namespace Rcpp;
using std::cout;


class TestClass {
  public:
    int value;

    TestClass(int initial_val) {
      value = initial_val;
    };

};


//[[Rcpp::export]]
SEXP get_test_obj() {
  Rcpp::XPtr<std::shared_ptr<TestClass>> ptr(std::make_shared<TestClass>(5), true);
  return ptr;
};

但是得到以下错误:

 no matching function for call to 'Rcpp::XPtr<std::shared_ptr<TestClass> >::XPtr(std::shared_ptr<TestClass>, bool)'

关于如何做到这一点的任何想法?或者我错了吗?

3 个答案:

答案 0 :(得分:6)

来自@ d3coy的回答几乎包含所有信息。 Rcpp::XPtr是一个模板智能指针类,它的参数是指针类,而不是它指向的类。因此Rcpp::XPtr<std::shared_ptr<TestClass>>是指向std::shared_ptr<TestClass>*的智能指针。请注意*,这是重要的一点。

shared_ptr超出范围时,如果它是原始指针的最后一个持有者,则原始指针可能会被删除。这绝对不是你想要的。

相反,您可以使用new创建一个原始指针,并使用XPtr提供delete。当垃圾邮件收集器收集R对象时,该指针将获得XPtr d,而make_unique不是,这是您在处理外部指针时通常需要的。

我知道当前的指南是尽可能使用make_sharednew而不是new,但在这种情况下,您需要XPtr。智慧来自shared_ptr,如果你将它与{{1}}混合,它们将会阻碍彼此。

答案 1 :(得分:5)

我怀疑R方会期望将std :: shared_ptr传递给它。我假设你的源代码中的其他一些代码依赖于std :: shared_ptr,但你想将内部原始指针传递给R.我还假设std :: shared_ptr的生命周期在你的代码中得到了更好的管理,因为所呈现的代码会使std :: shared_ptr在函数之后超出范围并在下一次取消引用时崩溃。

在任何情况下,如果你想将内部原始指针传递给R,你就会这样做(设计):

//[[Rcpp::export]]
SEXP get_test_obj() {
  std::shared_ptr<TestClass> s_ptr = std::make_shared<TestClass>(5);
  Rcpp::XPtr<TestClass> x_ptr(s_ptr.get(), true);
  return x_ptr;
};

答案 2 :(得分:2)

感谢所有的提示和'指针'。不确定这是否是正确的回应方式,但我想我会输入我找到的解决方案。

关键是R方确实不一定需要std::shared_ptr。但是,我正在与现有的C ++库连接。我需要实例化库的std::shared_ptr<TestClass>(使用R)并反馈到需要std::shared_ptr<TestClass>的C ++算法。

我解决它的方法如下(示例和未经测试):

#include <iostream>
#include <memory>
#include <Rcpp.h> 
using namespace Rcpp;
using std::cout;


class TestClass {
  public:
  int value;
  TestClass(int initial_val): value(initial_val) {}

};

class TestClassContainer {
  public
  std::shared_ptr<TestClass> test_class_obj;
  TestClassContainer(): test_class_obj(std::make_shared<TestClass>()) {} 
};

//[[Rcpp::export]]
SEXP get_test_obj() {
  Rcpp::XPtr<TestClassContainer> ptr(new TestClassContainer(), true);
  return ptr;
};

//[[Rcpp::export]]
SEXP do_something_with_shared_ptr_testclass(SEXP test_container_obj) {
  Rcpp::XPtr<ResourceContainer> test_ptr(test_container_obj);
  ExternalLib::do_function(test_container_obj->test_class_obj);
};

然后在R中我可以做到:

test_container <- get_test_obj()
do_something_with_shared_ptr_testclass(test_container)