[R] C++: SET_LENGTH() Over Many Iterations?

Jim Java jjava at priscian.com
Wed Dec 10 03:55:44 CET 2003


In a C++ extension to R (v 1.8.1), I've been experimenting with a
generic "push back" function to tack one value at a time onto the end
of an R vector created within the extension. After calling this
function a certain number of times Rgui.exe (I'm writing in Windows
using Visual Studio .NET 2003) will fail with an Access Violation,
which doesn't happen when I pre-allocate the R-vector memory and write
to the reserved slots; i.e., I'm not trying to create an R object too
big to be handled by R within the context of my OS's available memory.
Here's some simple test code I've been running:

<CPP Code>
  #define PUSH_BACK_INTEGER(v, x) \
    do {\
      UNPROTECT_PTR(v);\
      SET_LENGTH(v, GET_LENGTH(v) + 1);\
      PROTECT(v);\
      INTEGER_POINTER(v)[GET_LENGTH(v) - 1] = x;\
    }\
    while (false)

  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);
    if (full_alloc)
      PROTECT(int_vect = NEW_INTEGER(n_reps));
    else
      PROTECT(int_vect = NEW_INTEGER(0));

    for (int i = 0; i < n_reps; ++i) {
      Rprintf("  ** Iteration %d:\n", i + 1);
      if (full_alloc)
        INTEGER_POINTER(int_vect)[i] = i;
      else
        PUSH_BACK_INTEGER(int_vect, 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>

If allocate=TRUE (vector memory is pre-allocated in the extension),
the code proceeds normally on my system; if allocate=FALSE, Rgui.exe
eventually crashes from an Access Violation. I've gathered only enough
information from the R source code so far to think that R is
ultimately calling realloc() through the SET_LENGTH macro; that would
make my code rather inefficient, but I'm trying for genericness here.
In C++, is there a better way than what I'm doing to concatenate
values onto the end of an R vector of arbitrary length, especially
over many iterations?

Thanks for taking the time to read this.

System specs: Pentium 4 2.5 GHz, 512 MB RAM, 40 GB hard drive, Win XP

Yrs etc.,

Jim Java




More information about the R-help mailing list