Chapter 17 Rのオブジェクトを扱う際の注意点

17.1 ベクトル同士の代入

ベクトルや行列同士で代入する際に、単純に v2 = v1 で代入すると v1 の要素の値が v2 にコピーされるのではなく、v1 と v2 は同じオブジェクトに対する別名となります。そのため v1 の値を変更すると v2 の値も変更されてしまいます。それを避けるためには clone() 関数を使用します。すると v1 の値を変更しても、v2 の値は変更されません。

C++ に詳しい人のために説明すると、Rcpp のデータ型は内部にオブジェクトの値そのものではなく、オブジェクトへのポインタを保持しています。そのため、単純に v2 = v1 で代入すると v1 が指し示すオブジェクトへのポインターの値がコピーされるので v1 と v2 は同じオブジェクトを指し示す結果となります。これをシャロー(浅い)コピーと呼びます。それに対して、v2 = clone(v1) を用いた場合には、v1 が持つポインタが指し示すオブジェクトの値を複製して、新たに別のオブジェクトを作成します。これをディープ(深い)コピーと呼びます。

下のコード例では、浅いコピーと深いコピーの後に代入した元のベクトルの値を変更した時の結果の違いを示します。

C++に詳しい人のために説明すると、Rcppのデータ型は内部にオブジェクトの値そのものではなく、オブジェクトへのポインタを保持しています。そのため、単純に v2 = v1 で代入するとすると内部のポインターの値がコピーされてしまうので、このような現象が起きる。

17.2 要素番号の型

32 bit システムやバージョン 2 以前の R ではベクトルの要素番号には int 型が使われていたため、ベクトルの要素数の最大値は 2^31 - 1 となっていました。しかし、現在一般的となっている 64 bit システムにおけるバージョン3以降のRではこれよりも要素数の大きいベクトル(Long Vector)を扱うことができます。Rcpp で Long Vector をサポートするためには、要素数や要素番号を変数として保持する場合に int 型ではなく R_xlen_t 型を用います。64 bit システムでも要素番号として int 型を用いることもできますが、その場合には長さが 2^31 - 1 を超えるベクトルを渡された時に処理ができなくなります。

17.3 []演算子の返値

[]() 演算子でベクトルの要素へアクセスした時の返値は、Vectorそのものではなく Vector::Proxy という型となっています。そのため、v[] を他の関数の引数として与えるとコンパイルエラーになることがあります。その場合には、as<T>() を用いて、目的の型 T (NumericVector など) に変換します。

#四則演算と比較演算