从Rcpp函数接收结果后会话崩溃

时间:2017-01-12 05:41:27

标签: c++ r rcpp

以下代码正确编译和执行,但每次运行它时,我的R会话在完成后不久就会出现致命错误。我正在运行R版本3.3.2和Rtools 3.3。

我错过了什么吗?我如何追踪导致崩溃的原因?

#include<Rcpp.h>
using namespace Rcpp;

NumericMatrix dupCheckRcpp(NumericMatrix x) {
    int nrow, ncol;
    int i, j, k, m, n;
    bool flag;
    NumericMatrix dupMat(300,ncol);

    n = 0;
    nrow = 0; ncol = 0;
    nrow = x.nrow();
    ncol = x.ncol();

    for (i = 0; i < nrow - 1 ; ++i) {
        for (j = i + 1; j < nrow; ++j) {
            flag = TRUE;
            for (k = 0; k < ncol; ++k) {
                if (x(i,k) != x(j,k)) {
                    flag = FALSE;
                    break;
                }
            }
            if (flag == TRUE) {
                for (m = 0; m < ncol; ++m) {
                    dupMat(n,m) = x(i,m);
                }
                n = n + 1;
            }
        }
    }
    return dupMat;
}

1 个答案:

答案 0 :(得分:4)

您的代码存在一些问题。我们首先看一下如何定义结果矩阵,使用bool,然后通过矩阵子集详细解决未定义行为(UB)的问题。

定义:

NumericMatrix dupMat(300, ncol);

有两个问题:

  1. ncol初始化之前放置
  2. 假设x矩阵的nrow固定为300。
  3. 移动dupMat的实例化,直到ncolnrow初始化为止。或者,将其移动到您知道重复行数量之后。

    nrow = x.nrow();
    ncol = x.ncol();
    
    Rcpp::NumericMatrix dupMat(nrow, ncol); 
    

    此外,C ++中的bool值是用小写字母写的。

    也就是说,在设置true变量的值时,使用TRUE代替falseFALSE代替flag

    三种方法可以访问NumericMatrix中的各个元素,但是,我们只会关注使用{{}的两个 1}} indices。

    • i,j:以这种方式访问​​元素会导致边界检查和后续异常标志,如果该点不在范围内则会发出警告。从本质上讲,这种访问方法导致UB,因为(i,j)可以很容易地超越行索引。当RStudio或R运行后台任务导致崩溃发生时,UB可能会在稍后的时间点造成严重破坏。
    • n = n + 1:这是首选方法,因为它提供边界检查并抛出一个漂亮的例外,例如
      

    dupCheckRcpp(a)出错:索引越界

    由以下代码段触发:

    .at(i,j)

    if (flag == true) { for (m = 0; m < ncol; ++m) { Rcpp::Rcout << "dupMat (" << n << ","<< m << ")" << std::endl << "x (" << i << ","<< m << ")" << std::endl; dupMat.at(n, m) = x.at(i, m); } n = n + 1; // able to exceed nrow. } 达到上限的主要原因是放置在每次重新实例化的第二个 n = n + 1循环中。

    在不知道重复检查背后的意图的情况下,除了猜测它正在检查可能在矩阵中存在的重复。我要到此为止。