2016-12-18 10 views
1

私はRエクステンションを書くために使用しているサードパーティのCライブラリを持っています。私はS4オブジェクトの一部としてそれらを維持する必要があるライブラリ内で定義されたいくつかの構造体を作成する必要があります(これらの構造体を計算の状態に定義すると考えると、それらを破壊するのは残りのすべてを破棄することです計算とそのすべての結果が既に計算されている)。 ポインタを保持するS4オブジェクトを作成しようと考えていますが、これらの構造体はvoid*ポインタとしていますが、どのようにするのかはまったく分かりません。S4構造体へのポインタを持つオブジェクト

+1

https://stat.ethz.ch/R-manual/R-devel/library/methods/html/BasicClasses.html: 'externalptr' – hrbrmstr

答えて

5

としては、私はあなたが保存する必要がありますなぜ何らかの理由が表示されませんが、あなたが、執筆R拡張機能のthis sectionに触れされ、「生きている」ようなオブジェクトを維持するためにexternalptrタイプを使用することができ、@hrbrmstrによって指摘しました何でも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; 

newを介して作成ポインタを操作するときdefault finalizerは、単に保持された物体のdeleteを呼び出すためには、Rcpp::XPtr<SomeClass>を使用することが一般的に十分です。しかし、C APIを扱っているので、XPtrmallocによって割り当てられたメモリ上で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オブジェクトを削除して実行するガベージコレクタを強制します同様に

これらの関数をすべて1つの場所に格納するためのオプションの1つである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クラスではなく参照クラスを使用します)。

+3

優れた答え。おそらくRcppギャラリーの投稿にもなりますか? –

関連する問題