[R] C++: Appending Values onto an R-Vector.
Jim Java
jjava at priscian.com
Sun Dec 21 01:10:49 CET 2003
[Jim Java]
>Hi folks. I posted this question a few days ago, but maybe it got
>lost because of the code I included with it. I'm having a problem
>using the SET_LENGTH() macro in an R extension I'm writing in C++.
>In a function within the extension I use SET_LENGTH() to resize R
>vectors so as to allow the concatenation of single values onto the
>vectors -- it's a "push back" function to append values onto the
>end of a vector. However, when I use this function to push back a
>large number of values one at a time, Rgui.exe (I'm working with R
>1.8.1 in Windows XP) crashes from an Access Violation; if, however,
>I pre-allocate space (is the space actually pre-allocated?) for the
>vector (say with NEW_INTEGER(n) rather than NEW_INTEGER(0)) and
>insert values into the allocated slots, the code works fine. If
>you'd like to see some test code, I've already posted it here:
>
>https://www.stat.math.ethz.ch/pipermail/r-help/2003-December/041871.html
>
>Here's my question, then: Is SET_LENGTH() the appropriate way to
>create space for tacking values onto the end of an R-vector in C++,
>or should I be trying to tack them on in some other way?
[Brian Ripley]
>You UNPROTECT before calling lengthgets, and that is I think part
>of your problem. You need to use REPROTECT...
[Jim Java]
This problem is solved, so I want to post a follow-up for reference
in the archives. My thanks to Prof. Ripley for helping me out: the
problem was indeed in using UNPROTECT before lengthgets() rather than
using REPROTECT afterwards. My revised test code is listed below, also
for reference.
<CPP Code>
SEXP R_SimplePushBackTest(SEXP args)
{
SEXP arg1, arg2, int_vect;
PROTECT(arg1 = AS_INTEGER(CADR(args)));
int n_reps = INTEGER_POINTER(arg1)[0];
PROTECT(arg2 = AS_LOGICAL(CADDR(args)));
bool full_alloc = (LOGICAL_POINTER(arg2)[0] ? true : false);
PROTECT_INDEX int_vect_pindex;
if (full_alloc)
PROTECT_WITH_INDEX(int_vect = NEW_INTEGER(n_reps), &int_vect_pindex);
else
PROTECT_WITH_INDEX(int_vect = NEW_INTEGER(0), &int_vect_pindex);
for (int i = 0; i < n_reps; ++i) {
Rprintf(" ** Iteration %d:\n", i + 1);
if (full_alloc)
INTEGER_POINTER(int_vect)[i] = i;
else {
// This works now! --
SET_LENGTH(int_vect, GET_LENGTH(int_vect) + 1);
REPROTECT(int_vect, int_vect_pindex);
INTEGER_POINTER(int_vect)[GET_LENGTH(int_vect) - 1] = i;
}
}
SEXP out, names, cls;
PROTECT(out = NEW_LIST(1));
SET_VECTOR_ELT(out, 0, int_vect);
PROTECT(names = NEW_CHARACTER(1));
SET_STRING_ELT(names, 0, COPY_TO_USER_STRING("integer.vector"));
SET_NAMES(out, names);
PROTECT(cls = NEW_CHARACTER(1));
SET_STRING_ELT(cls, 0, COPY_TO_USER_STRING("pushback"));
classgets(out, cls);
UNPROTECT(6);
return out;
}
</CPP Code>
<R Code>
nreps=50000
allocate=FALSE
sink("pushback_test.txt")
test.pushback=.External("R_SimplePushBackTest", as.integer(nreps), as.logical(allocate))
print(test.pushback)
sink()
</R Code>
More information about the R-help
mailing list