以下代码正确编译和执行,但每次运行它时,我的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;
}
答案 0 :(得分:4)
您的代码存在一些问题。我们首先看一下如何定义结果矩阵,使用bool
,然后通过矩阵子集详细解决未定义行为(UB)的问题。
定义:
NumericMatrix dupMat(300, ncol);
有两个问题:
ncol
初始化之前放置x
矩阵的nrow
固定为300。移动dupMat
的实例化,直到ncol
和nrow
初始化为止。或者,将其移动到您知道重复行数量之后。
nrow = x.nrow();
ncol = x.ncol();
Rcpp::NumericMatrix dupMat(nrow, ncol);
此外,C ++中的bool
值是用小写字母写的。
也就是说,在设置true
变量的值时,使用TRUE
代替false
和FALSE
代替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
循环中。
在不知道重复检查背后的意图的情况下,除了猜测它正在检查可能在矩阵行中存在的重复。我要到此为止。