【问题标题】:How to initialize NumericVector to a specific size after it has been declared?声明后如何将 NumericVector 初始化为特定大小?
【发布时间】:2015-05-08 17:55:30
【问题描述】:

我编写了以下 Rcpp 代码,它可以编译但没有给出预期的结果。

    // [[Rcpp::export]]
RObject test_1 (Rcpp::NumericVector& x)
{
  NumericVector x1;
  if (x.size() < 5)
  {
    NumericVector x1(x.size()*3);
    for (int ii = 0; ii < x.size(); ii++)
    {
      x1[ii] = sqrt(x[ii]);
    }
  }
  else
  {
    NumericVector x1(x.size()*2);
    for (int ii = 0; ii < x.size(); ii++)
    {
      x1[ii] = sqrt(x[ii]);
    }
  }
  return x1;
}

x1,返回向量在 if 语句之外声明,返回向量 x1 的大小可以变化。但是如果我用它创建一个新对象的大小声明 NumericVector,但返回的 x1 是一个空向量。

以下代码有效:

// [[Rcpp::export]]
RObject test (const Rcpp::NumericVector& x)
{
  NumericVector x1;
  if (x.size() < 5)
  {
    NumericVector tmp(x.size()*3);
    for (int ii = 0; ii < x.size(); ii++)
    {
      tmp[ii] = sqrt(x[ii]);
    }
    x1 = tmp;
  }
  else
  {
    NumericVector tmp(x.size()*2);
    for (int ii = 0; ii < x.size(); ii++)
    {
      tmp[ii] = sqrt(x[ii]);
    }
    x1 = tmp;
  }
  return x1;
}

在这里我声明了 temp numericvector,然后将 x1 设置为该向量。

我前段时间做过,知道有一种方法可以在声明 NumericVector 后将其设置为特定大小,但我只是不记得如何了。

编辑:编辑代码和问题以显示在 if 语句之前返回向量大小是如何未知的。

【问题讨论】:

  • "(我知道示例中不是这种情况)" - 请用您的情况的代表性示例阐明您的问题。
  • 我不知道r,但我是从 C++ 的角度来看的。如果编译了这段代码,那么 RObject 应该有一个接受 NumericVector 的构造函数,以便正确复制返回值,并创建一个新的RObject。换句话说,代码不应该崩溃,因为我没有看到客户端(您的)代码中正在进行任何指针操作。
  • @Alvin 我对你的目标有点困惑——不管x 的大小,只有x1 的第一个x.size() 元素将被赋予值(sqrt(x[ii]) )。在x.size() &lt; 5 的情况下,x1 中的[x.size(), 3*x.size()-1] 值范围将默认初始化为0,在x.size() &gt;= 5 的情况下,x1 中的[x.size(), 2*x.size()-1] 值范围将是默认初始化为0。对吗?
  • 目标是在 if 语句中将 x1 设置为特定大小。其他一切都是次要的。我可以用我喜欢的任何值填充 x1,但这并不重要,我只想将 x1 设置为特定大小,而不必创建 tmp 向量并将 x1 设置为等于该值。谢谢。

标签: c++ r rcpp


【解决方案1】:

你可以使用这种风格:

NumericVector x;
if (foo)
    x = NumericVector(1);
else
    x = NumericVector(2);

甚至(如果你想避免生成向量的零初始化)

x = static_cast<NumericVector>(no_init(size));

注意写的时候

NumericVector x;
if (foo)
    NumericVector x(1);

您实际上是在创建两个名为xNumericVector 对象——一个位于顶级范围内,一个位于if 语句的范围内。

也就是说,写的时候值得理解

NumericVector x;

您实际上是在创建一个对象,而不仅仅是声明一个对象(这仅适用于内置类型,例如int)。因此,当您编写 NumericVector x 时,x 实际上是使用零参数 NumericVector 构造函数默认构造的(创建长度为 0 的数字向量)

【讨论】:

    【解决方案2】:

    你可以有条件地 resize 一个 std::vector&lt;double&gt;Rcpp::wrap() 它,像这样:

    #include <Rcpp.h>
    // [[Rcpp::export]]
    Rcpp::RObject test_1(const Rcpp::NumericVector& x) {
    
      std::vector<double> x1;
      if (x.size() < 5) {
        x1.resize(3*x.size());
      } else {
        x1.resize(2*x.size());
      }
      for (int ii = 0; ii < x.size(); ii++) {
        x1[ii] = sqrt(x[ii]);
      }
      return Rcpp::wrap(x1);
    }
    
    /*** R
    
    xa <- 1:3
    xb <- 1:10
    
    test_1(xa)
    # [1] 1.000000 1.414214 1.732051 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
    
    test_1(xb)
    #[1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 3.000000 3.162278 0.000000 0.000000
    [13] 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
    
    length(test_1(xa))/length(xa)
    #[1] 3
    length(test_1(xb))/length(xb) 
    #[1] 2
    
    */
    

    【讨论】:

    • 谢谢,但问题是当您不知道 x1 应该在 for 循环之前的大小时。我将修改原始问题以使其更清楚。
    • 感谢 nrussell,这也可以。只是想知道 x1 是否已经是一个大向量,.resize() 是复制每个元素还是只是在末尾有效地添加一个新向量?
    【解决方案3】:

    你可以这样做

    RObject test_1 (Rcpp::NumericVector x)
    {
        for (int ii = 0; ii < x.size(); ii++)
        {
           x[ii] = sqrt(x[ii]);
        }
        return x;
    }
    

    通过传递值,您可以创建一个与原始NumericVector 大小相同的新NumericVector

    如果您不想更改 API,则第二个代码可以,但不需要临时变量

     RObject test_1 (const Rcpp::NumericVector& x)
    {
        NumericVector x1(x.size());
        for (int ii = 0; ii < x.size(); ii++)
        {
           x1[ii] = sqrt(x[ii]);
        }
        return x1;
    }
    

    【讨论】:

    • 看来您正在更改 x 的原始值并返回该值。虽然这可行,但我正在尝试学习如何在不同范围内使用未知大小的向量。这就是为什么我在 for 循环或 if 语句之外声明 x1,但在循环内分配适当的大小。
    • @PaulMcKenzie 这在抽象意义上是好的和真实的,但在这里是不可避免的。我们在给定的 API 范围内操作——请参阅SEXP 类型上的 R 语言定义。
    • @DirkEddelbuettel 好吧,如果它们是指针类型,那么代码会在返回指向局部变量的指针时产生未定义的行为。
    • @PaulMcKenzie 让我们离线。您正在查看 Rcpp 答案;这里还有几百个其他的 Q 和 As;请环顾四周和/或查看其他 Rcpp 文档——以及提供交给 Rcpp 的接口的 R 文档。
    • 确切地说,NumericVectors 是代理对象——它们只是包含指向某些数据的指针;它们本身并不是真正的指针类型。因此,复制NumericVector 相当于复制一个包含指向某些数据的指针的对象(其生命周期由 RAII + R 自己的内存管理系统管理)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多