Rcpp 中值和参考参数之间的差异

Hon*_*Ooi 5 c++ r 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;
}")
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,func1将其x作为参考参数,而func2将其作为值。如果这是常规的 C++,我会将其理解为func1允许更改调用代码中的值x,而这不会在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
Run Code Online (Sandbox Code Playgroud)

因此,就参数的副作用而言,它看起来func1和行为方式都是相同的。func2

这是什么原因呢?一般来说,通过引用还是通过值将参数传递给 Rcpp 函数更好?

Chi*_*iel 1

首先,您的两个函数都返回一个NumericVector未分配给任何变量的值,因此未使用。下面的代码与您所拥有的代码等效,因为您NumericVector无论如何都会丢弃返回的代码。

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)
Run Code Online (Sandbox Code Playgroud)

其次,aNumericVector在 C++ 函数中充当指针。指针为您提供存储值的地址,并且为了能够更改该地址处的值,您只需要知道该地址,但不需要具有修改地址本身的能力。因此,按值传递指针或按引用传递指针没有区别。

该线程包含有关以下行为的有用知识NumericVector

我应该更喜欢 Rcpp::NumericVector 而不是 std::vector 吗?

下面的程序演示了 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;
}
Run Code Online (Sandbox Code Playgroud)