Rcpp 模块:将对成员变量 c++ 对象的引用返回给 R

Rcpp modules: Returning a reference to a member variable c++ object to R

我有一个 C++ class,它将指向同类对象的原始指针存储为成员变量。 class 通过 Rcpp 模块暴露给 R。我想 return 通过 属性 对成员变量的引用。但是,副本似乎是 returned.

这也适用于将不同的成员变量对象 returned 到 R 的其他情况。

最小可重现示例

我使用 Rcpp::Rcpp.package.skeleton('testmod', module = TRUE) 创建了一个新的骨架包并添加了我自己的 class Foo,将其暴露给 R。示例可以在 here 上找到 github.

src/Foo.cpp 的内容:

#include <Rcpp.h>

class Foo;
RCPP_EXPOSED_CLASS(Foo)

class Foo
{
  public:
    Foo():
      ancestor_ptr(NULL){}
    Foo(const Foo& ancestor):
      ancestor_ptr(&ancestor){}

    const Foo& get_ancestor() {return *ancestor_ptr;}

    const Foo* ancestor_ptr;
};


RCPP_MODULE(mymodule){
  using namespace Rcpp ;

  class_<Foo>("Foo")
    .default_constructor()
    .constructor<const Foo&>()
    .property("ancestor", &Foo::get_ancestor)
    ;
}

在 R 会话中测试得到:

>library(testmod)
>a <- new(Foo)
>b <- new(Foo, a)
>a
C++ object <0x1c57108> of class 'Foo' <0x22d78b0>
>b$ancestor
C++ object <0x1f8ffa0> of class 'Foo' <0x22d78b0>

所以 0x1c57108 != 0x1f8ffa0,我检查了未显示的辅助函数,发现 0x1c57108 实际上是对象 a.

的地址

编辑 我刚刚在 uuid 成员变量和自定义复制构造函数的帮助下进行了检查,实际上正在制作成员对象的副本。

实际情况是模块无法真正处理返回的引用,因此在调用 get_ancestor 时会生成一个副本。

考虑一下您的代码的这个扩展版本:

#include <Rcpp.h>

class Foo;
RCPP_EXPOSED_CLASS(Foo)

  class Foo
  {
  public:
    Foo():
    ancestor_ptr(NULL){}
    Foo(const Foo& ancestor):
      ancestor_ptr(&ancestor)
    {
      Rprintf( "Foo(const Foo&)\n")  ;  
    }

    const Foo& get_ancestor() {return *ancestor_ptr;}
    const Foo* ancestor_ptr;

    void print_ptr(){
      Rprintf( "ptr = %p\n", this ) ;
    }

    void print_ancestor_ptr(){
      Rprintf( "ptr = %p\n", ancestor_ptr ) ;
    }

  };


RCPP_MODULE(mymodule){
  using namespace Rcpp ;

  class_<Foo>("Foo")
    .default_constructor()
    .constructor<const Foo&>()
    .property("ancestor", &Foo::get_ancestor)
    .method( "print_ptr", &Foo::print_ptr )
    .method( "print_ancestor_ptr", &Foo::print_ancestor_ptr )
  ;
}

当您调用复制构造函数时会创建一个副本,这很好,您的意思是:

> a  <- new( Foo )
> b <- new( Foo, a )
Foo(const Foo&)

但是当你调用 get_ancestor 时也会生成一个:

> b$ancestor
Foo(const Foo&)
C++ object <0x10204ee00> of class 'Foo' <0x10207c7c0>

但是,在 b 中您确实存储了正确的指针:

> a$print_ptr()
ptr = 0x113278820
> b$print_ancestor_ptr() 
ptr = 0x113278820