R 확장을 작성하는 데 사용하는 타사 C 라이브러리가 있습니다. 나는 라이브러리에 정의 된 몇 가지 구조체를 만들어서 S4 객체의 일부로 유지해야 할 필요가있다. (이 구조체를 계산 상태로 정의하는 것으로 생각하고 파괴하기 위해 나머지 모든 객체를 파괴해야한다. 계산 및 이미 계산 된 모든 결과). 포인터를 이러한 구조체를 void*
포인터로 유지하는 S4 개체를 만드는 것이 생각 중입니다. 그렇지만 그렇게하는 방법은 분명하지 않습니다. 슬롯의 형식은 무엇입니까? 당신이 저장해야 할 이유는 어떤 이유가 표시되지 않지만S4 구조체에 대한 포인터가있는 객체
답변
바와 같이 @hrbrmstr 지적, 당신은, 쓰기 R 확장의 this section에에 감동하는 "살아"등의 개체를 유지하기 위해 externalptr
유형을 사용할 수 있습니다 뭐든지 void*
. C++을 조금 사용하는 데 문제가 없다면 Rcpp class XPtr
은 EXTPTRSXP
을 관리하는 데 필요한 상당한 양의 상용구를 제거 할 수 있습니다. 예를 들어, 다음과 같은 간단한 예는 당신의 타사 라이브러리의 API를 나타냅니다 가정
#include <Rcpp.h>
#include <stdlib.h>
typedef struct {
unsigned int count;
double total;
} CStruct;
CStruct* init_CStruct() {
return (CStruct*)::malloc(sizeof(CStruct));
}
void free_CStruct(CStruct* ptr) {
::free(ptr);
::printf("free_CStruct called.\n");
}
typedef Rcpp::XPtr<CStruct, Rcpp::PreserveStorage, free_CStruct> xptr_t;
default finalizer 단순히 열린 개체에 대한 delete
를 호출하기 때문에, Rcpp::XPtr<SomeClass>
를 사용하는 것이 일반적으로 충분하다 new
통해 생성 된 포인터 작업. 그러나 C API를 다루므로, XPtr
이 malloc
을 통해 할당 된 메모리에 delete
을 호출하지 않도록 (기본값) 템플릿 매개 변수 Rcpp::PreserveStorage
및 더 중요한 것은 적합한 종료 자 (이 예에서는 free_CStruct
)를 제공해야합니다. 해당 R 객체가 가비지 수집 될 때 등. 예를 계속
, 당신은 당신의 CStruct
와 상호 작용하는 다음과 같은 기능을 쓰기 가정
-
:
// [[Rcpp::export]]
xptr_t MakeCStruct() {
CStruct* ptr = init_CStruct();
ptr->count = 0;
ptr->total = 0;
return xptr_t(ptr, true);
}
// [[Rcpp::export]]
void UpdateCStruct(xptr_t ptr, SEXP x) {
if (TYPEOF(x) == REALSXP) {
R_xlen_t i = 0, sz = XLENGTH(x);
for (; i < sz; i++) {
if (!ISNA(REAL(x)[i])) {
ptr->count++;
ptr->total += REAL(x)[i];
}
}
return;
}
if (TYPEOF(x) == INTSXP) {
R_xlen_t i = 0, sz = XLENGTH(x);
for (; i < sz; i++) {
if (!ISNA(INTEGER(x)[i])) {
ptr->count++;
ptr->total += INTEGER(x)[i];
}
}
return;
}
Rf_warning("Invalid SEXPTYPE.\n");
}
// [[Rcpp::export]]
void SummarizeCStruct(xptr_t ptr) {
::printf(
"count: %d\ntotal: %f\naverage: %f\n",
ptr->count, ptr->total,
ptr->count > 0 ? ptr->total/ptr->count : 0
);
}
// [[Rcpp::export]]
int GetCStructCount(xptr_t ptr) {
return ptr->count;
}
// [[Rcpp::export]]
double GetCStructTotal(xptr_t ptr) {
return ptr->total;
}
// [[Rcpp::export]]
void ResetCStruct(xptr_t ptr) {
ptr->count = 0;
ptr->total = 0.0;
}
이 시점에서
, 당신은 R에서 CStructs
처리를 시작하는 데 충분했을
ptr <- MakeCStruct()
은 CStruct
을 초기화하고 externalptr
으로 저장합니다.UpdateCStruct(ptr, x)
CStruct
에 저장된 데이터를 수정합니다, SummarizeCStruct(ptr)
이 요약을 인쇄합니다 등rm(ptr); gc()
따라서 free_CStruct(ptr)
를 호출하고 사물의 C 측의 오브젝트를 파괴의 ptr
개체를 제거하고 실행하는 가비지 콜렉터를 강제로 또한이러한 기능을 모두 한 곳에서 사용하기위한 하나의 옵션 인 S4 클래스 사용에 대해 언급했습니다. 그런 다음
setClass(
"CStruct",
slots = c(
ptr = "externalptr",
update = "function",
summarize = "function",
get_count = "function",
get_total = "function",
reset = "function"
)
)
setMethod(
"initialize",
"CStruct",
function(.Object) {
[email protected] <- MakeCStruct()
[email protected] <- function(x) {
UpdateCStruct([email protected], x)
}
[email protected] <- function() {
SummarizeCStruct([email protected])
}
[email protected]_count <- function() {
GetCStructCount([email protected])
}
[email protected]_total <- function() {
GetCStructTotal([email protected])
}
[email protected] <- function() {
ResetCStruct([email protected])
}
.Object
}
)
, 우리는이 같은 CStruct
들과 함께 작업 할 수 있습니다 :
ptr <- new("CStruct")
[email protected]()
# count: 0
# total: 0.000000
# average: 0.000000
set.seed(123)
[email protected](rnorm(100))
[email protected]()
# count: 100
# total: 9.040591
# average: 0.090406
[email protected](rnorm(100))
[email protected]()
# count: 200
# total: -1.714089
# average: -0.008570
[email protected]()
[email protected]()
# count: 0
# total: 0.000000
# average: 0.000000
rm(ptr); gc()
# free_CStruct called.
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 484713 25.9 940480 50.3 601634 32.2
# Vcells 934299 7.2 1650153 12.6 1308457 10.0
물론
, 다른 옵션이있는 더 많거나 적은, Rcpp Modules을 사용하는 것입니다 여기에 하나의 가능성이다 R 측면의 클래스 정의 상용구를 처리하십시오 (단, S4 클래스보다는 참조 클래스 사용).
우수 답변. 아마도 Rcpp Gallery 게시물 일 수도 있습니까? –
https://stat.ethz.ch/R-manual/R-devel/library/methods/html/BasicClasses.html :'externalptr' – hrbrmstr