Rcpp: segfault для массивов › 698152, если объявлен IntegerVector

Я сталкиваюсь с тем, что, вероятно, является проблемой памяти с кодом С++, связанным с Rcpp. Я мог бы придумать следующий минимальный тестовый пример:

тест.Р:

require(Rcpp)
sourceCpp("test.cpp")
N <- 698153
testCpp(N)

test.cpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]] 
void testCpp(int N) {
    double closestLandmarks[N];
    int closestLandmarksIdx[N];
    IntegerVector l(10);
    // Fill the double and int vectors
    for (int j = 0; j < N; j++) {
        closestLandmarks[j] = 1;
        closestLandmarksIdx[j] = 2;
    } // j

    return;
}

Запуск Rscript test.R приводит к переполнению стека: Error: segfault from C stack overflow. По сути, этот код выделяет два массива размера N (неважно, являются ли они целыми или двойными, они будут падать одинаково), создает экземпляр IntegerVector размера 10 и заполняет первые 2 позиции массивов. Я могу в основном удалить любую строку здесь, и она не рухнет. Он также не будет падать с N ‹ 698153 (это критическое число немного варьируется от машины к машине... 500000 кажется всегда безопасным, в то время как 1e6 падает везде). Он выйдет из строя, если я буду повторять только до j ‹ 2 вместо j ‹ N, то есть когда он попытается заполнить 2-ю позицию массивов.

Я не совсем понимаю, почему я должен столкнуться с проблемами памяти с двумя массивами, которые я считаю довольно маленькими (‹ 106) и очень маленьким IntegerVector. На моей машине много свободной оперативной памяти (5 ГБ из 24 ГБ), и я могу без проблем использовать гораздо большие векторы/матрицы в R.

Я явно пропускаю что-то очень глупое здесь. Что не так с моим кодом?


person Calimo    schedule 14.06.2013    source источник
comment
У вас не заканчивается память, у вас переполнение стека! (каламбур :p) Кстати, такой код, как double closestLandmarks[N]; (где N — переменная), даже не должен компилироваться (или, по крайней мере, должен выдавать предупреждение!), это массив переменной длины и это C99 и не стандартный С++   -  person gx_    schedule 14.06.2013
comment
Возможно, мы даже захотим удалить теги 'rcpp' и 'r' - это всего лишь вопрос C++.   -  person Dirk Eddelbuettel    schedule 14.06.2013


Ответы (2)


double closestLandmarks[N];
int closestLandmarksIdx[N];

оба размещаются в стеке. При большом N стек будет переполняться, а это означает, что в стеке мало места.

Вы можете разместить объекты в куче. std::vector сделает это за вас. Я бы предложил:

std::vector<double> closestLandmarks(N);
std::vector<int> closestLandmarksIdx(N);

Это интересная ссылка для чтения, которая учит вас различать стек и кучу: http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

person Enigma    schedule 14.06.2013
comment
Я знал, что упускаю что-то очень глупое. Спасибо за ссылку, она тоже очень полезна. - person Calimo; 14.06.2013

У вас заканчивается пространство стека. Для стека (где хранятся локальные переменные) выделяется столько памяти. Вам нужно использовать динамическое размещение:

double *closestLandmarks = new double[N];
int *closestLandmarksIdx = new int[N];

... 

delete [] closestLandmarks;
delete [] closestLandmarksIdx; 

(Или используйте вектор, как предложено в другом ответе).

person Mats Petersson    schedule 14.06.2013