Rcpp 中的值和参考参数之间的差异
考虑这两个函数:
library(Rcpp)
cppFunction("NumericVector func1(NumericVector &x)
{
for (int i = 0; i < x.length(); i++)
x[i] = x[i] * 2;
return x;
}")
cppFunction("NumericVector func2(NumericVector x) // no &
{
for (int i = 0; i < x.length(); i++)
x[i] = x[i] * 2;
return x;
}")
唯一的区别是 func1
将 x
作为参考参数,而 func2
将其作为值.如果这是常规的 C++,我会将其理解为允许 func1
在调用代码中更改 x
的值,而这不会发生在 func2
.
The only difference is that func1
takes x
as a reference parameter, whereas func2
takes it as a value. If this was regular C++, I'd understand this as func1
being allowed to change the value of x
in the calling code, whereas this won't happen in func2
.
然而:
> x <- 1:10/5 # ensure x is numeric, not integer
> x
[1] 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0
> func1(x)
[1] 0.4 0.8 1.2 1.6 2.0 2.4 2.8 3.2 3.6 4.0
> x
[1] 0.4 0.8 1.2 1.6 2.0 2.4 2.8 3.2 3.6 4.0 # x in calling env has been modified
> x <- 1:10/5 # reset x
> x
[1] 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0
> func2(x)
[1] 0.4 0.8 1.2 1.6 2.0 2.4 2.8 3.2 3.6 4.0
> x
[1] 0.4 0.8 1.2 1.6 2.0 2.4 2.8 3.2 3.6 4.0 # x is also modified
因此,就参数的副作用而言,func1
和 func2
的行为方式相同.
So it looks like func1
and func2
behave the same way, as far as side-effects on the arguments are concerned.
这是什么原因?一般来说,给 Rcpp 函数传递参数是按引用好还是按值好?
What is the reason for this? In general, is it better to pass arguments to Rcpp functions by reference or by value?
首先,您的两个函数都返回一个 NumericVector
,它没有分配给任何变量,因此没有被使用.下面的代码等同于您拥有的代码,因为您无论如何都会丢弃返回的 NumericVector
.
First, both your functions return a NumericVector
that is not being assigned to any variable, and therefore is not being used. The code below is equivalent to what you have, as you are discarding the returned NumericVector
anyhow.
cppFunction("void func1(NumericVector& x)
{
for (int i = 0; i < x.length(); i++)
x[i] = x[i] * 2;
}")
cppFunction("void func2(NumericVector x) // no &
{
for (int i = 0; i < x.length(); i++)
x[i] = x[i] * 2;
}")
x <- 1:10/5
func1(x)
print(x)
x <- 1:10/5
func2(x)
print(x)
其次,NumericVector
在 C++ 函数中表现为指针.指针为您提供了存储值的地址,为了能够更改该地址处的值,您只需要知道地址,但不需要修改地址本身的能力.因此,按值传递指针和按引用传递没有区别.
Second, a NumericVector
behaves as a pointer in the C++ functions. The pointer gives you the address where the values are stored, and to be able to change the values at that address, you only need to know the address, but you don't need the ability to modify the address itself. Therefore, there is no difference in passing the pointer by value or passing it by reference.
此线程包含有关 NumericVector
行为的有用知识:
This thread contains useful knowledge on the behavior of NumericVector
:
我应该更喜欢 Rcpp::NumericVector 而非 std::vector 吗?
下面的程序在 C++ 中演示了相同的行为.
The program below demonstrates the same behavior in C++.
#include <iostream>
void func1(double* a) // The pointer is passed by value.
{
for (int i=0; i<3; ++i)
a[i] *= 2;
}
void func2(double*& a) // The pointer is passed by reference.
{
for (int i=0; i<3; ++i)
a[i] *= 2;
}
void print(double* a)
{
std::cout << "Start print:" << std::endl;
for (int i=0; i<3; ++i)
std::cout << a[i] << std::endl;
}
int main()
{
double* x = new double[3];
// Set the values with 1, 2, and 3.
for (int i = 0; i<3; ++i)
x[i] = i+1;
print(x);
func1(x);
print(x);
// Reset the values with 1, 2, and 3.
for (int i = 0; i<3; ++i)
x[i] = i+1;
// This block shows the same behavior as the block above.
print(x);
func2(x);
print(x);
delete[] x;
}