使用外部指针进行奇怪的访问

Weird access with external pointers

我做了一个可重现的小例子:

#include <Rcpp.h>
using namespace Rcpp;

class Index {
public:
  Index(int i_) : i(i_) {}
  int getI() { return i; }
private:
  int i;
};

// [[Rcpp::export]]
SEXP getXPtrIndex(int i) {
  Rcout << "getXPtrIndex: i = " << i << std::endl;
  Index ind(i);
  Rcout << "getXPtrIndex: ind.i = " << ind.getI() << std::endl;
  return XPtr<Index>(&ind, true);
}

// [[Rcpp::export]]
void getXPtrIndexValue(SEXP ptr) {
  XPtr<Index> ind_ptr(ptr);
  Rcout << "getXPtrIndexValue: ind_ptr->i = " << ind_ptr->getI() << std::endl;
  Index ind = *ind_ptr;
  Rcout << "getXPtrIndexValue: ind.i = " << ind.getI() << std::endl;
}

基本上,我定义了一个小的 class,以及一个函数来获取此 class 的元素的外部指针。最后一个函数用于在将 class 元素返回给 C++ 时打印奇怪的访问器。

R 中的结果:

> (extptr <- getXPtrIndex(10))
getXPtrIndex: i = 10
getXPtrIndex: ind.i = 10
<pointer: 0x7ffeeec31b00>

> getXPtrIndexValue(extptr)
getXPtrIndexValue: ind_ptr->i = 33696400
getXPtrIndexValue: ind.i = 0

为什么我无法访问 10

我正在使用 Rcpp 版本 0.12.12(我认为是最新的)。

这似乎与临时对象有关---当您的第二个函数运行时,第一个函数的 "content" 已经消失了。

所以要么让

Index ind(10);

a global,并注释掉第一个函数中的行。然后一切都很好(我稍微改变了 R 调用):

R> extptr <- getXPtrIndex(10)
getXPtrIndex: i = 10
getXPtrIndex: ind.i = 10

R> getXPtrIndexValue(extptr)
getXPtrIndexValue: ind_ptr->i = 10
getXPtrIndexValue: ind.i = 10
R> 

或者当你让你 Index object static 以确保持久性时,它也以相同的方式工作。更正以下示例。

#include <Rcpp.h>
using namespace Rcpp;

class Index {
public:
  Index(int i_) : i(i_) {}
  int getI() { return i; }
private:
  int i;
};

// [[Rcpp::export]]
SEXP getXPtrIndex(int i) {
  Rcout << "getXPtrIndex: i = " << i << std::endl;
  static Index ind(i);
  Rcout << "getXPtrIndex: ind.i = " << ind.getI() << std::endl;
  return XPtr<Index>(&ind, true);
}

// [[Rcpp::export]]
void getXPtrIndexValue(SEXP ptr) {
  XPtr<Index> ind_ptr(ptr);
  Rcout << "getXPtrIndexValue: ind_ptr->i = " << ind_ptr->getI() << std::endl;
  Index ind = *ind_ptr;
  Rcout << "getXPtrIndexValue: ind.i = " << ind.getI() << std::endl;
}

/*** R
extptr <- getXPtrIndex(10)
getXPtrIndexValue(extptr)
*/