[R] anyone has C++ STL classes stability issue if used with R

Oleg Sklyar osklyar at ebi.ac.uk
Tue Feb 13 14:06:16 CET 2007


Duncan,

you are right about Rf_..., otherwise the lengths are checked in the R 
side, this is just one of the functions I have in the package and all 
arguments are thoroughly checked.

But apparently, the same code if redefined for using pointers instead of 
references works just perfectly fine (given below). And I do not see why 
the one I posted before fails. I will try to run it outside of R to see 
if the issue is anyhow connected to R.

// comparison operator redefined for pointers:
struct Pixel_compare: public binary_function<Pixel*, Pixel*, bool> {
     bool operator() (Pixel* a, Pixel* b) {
         return a->intens < b->intens;
     }
};
// was:
// struct Pixel_compare: public binary_function<Pixel&, Pixel&, bool> {
//    bool operator() (Pixel& a, Pixel& b) {
//        return a.intens < b.intens;
//    }
// };


// the queue redefined for pointers
typedef priority_queue<Pixel*, vector<Pixel*>, Pixel_compare> PixelPrQueue;
// was: typedef priority_queue<Pixel, vector<Pixel>, Pixel_compare> 
PixelPrQueue;

SEXP
lib_filterInvWS (SEXP x) {
     SEXP res;
     int i, j, index;
     double val;

     int nx = INTEGER ( GET_DIM(x) )[0];
     int ny = INTEGER ( GET_DIM(x) )[1];
     int nz = INTEGER ( GET_DIM(x) )[2];
     int nprotect = 0;

     PROTECT ( res = Rf_duplicate(x) );
     nprotect++;

     for (int im = 0; im < nz; im++ ) {
         double * src = &( REAL(x)[ im * nx * ny ] );
         double * tgt = &( REAL(res)[ im * nx * ny ] );

         PixelPrQueue pq;
         for ( j = 0; j < ny; j++ )
             for ( i = 0; i < nx; i++ ) {
                 index = i + nx * j;
                 val = src[ index ];
                 if ( val > BG ) {
                     tgt[ index ] = -1;
// new pixels are created as pointer to objects
// was: pq.push( Pixel(i, j, val) );
                     pq.push( new Pixel(i, j, val) );
                     continue;
                 }
                 tgt[ index ] = BG;
             }
// printed and all pointers deleted
         Pixel * px;
         while ( !pq.empty() ) {
             px = pq.top();
             pq.pop();
             Rprintf("%f\n", px->intens);
             delete px;
         }

     }

     UNPROTECT (nprotect);
     return res;
}

The above works fine. The "Compare" operator is defined differently from 
my previous post, but both fail if used with references.
Oleg

Duncan Murdoch wrote:
> On 2/13/2007 3:55 AM, Oleg Sklyar wrote:
>> Hello,
>>
>> is there any one who uses C++ STL classes when programming shared libs 
>> for R and has had any problems with STL?
> 
> I don't, but I'd suggest asking a technical question like this on 
> R-devel instead of R-help if you don't get help here.
> 
> I can see a few probably innocuous changes I'd suggest in your code 
> below, but nothing obvious:  use Rinternals.h instead of Rdefines.h, 
> don't use the Rf_ prefix, check the length of inputs before working with 
> the values.
> 
> Duncan Murdoch
> 
>>
>> In the very simple example below I am constantly getting segfaults 
>> when trying to populate the queue. The segfault occurs at what looks 
>> like a random index in the loop when pushing another element to the 
>> queue. Reproduced on 4 machines. Object x is an Image as in EBImage, 
>> i.e. a 3D R-array of numerics for the purpose of this code.
>>
>> LENGTH(x) can be up to 1e6 and the number of elements potentially to 
>> be in the queue is about 20% of those. But I get segfaults often on a 
>> third of fours element being added.
>>
>> Tried on R2.5.0-devel, R2.4.1-release and all machines were 64bit 
>> Linux with kernels 2.6.9 (stable CentOS), 2.6.17 (stable Ubuntu) and 
>> 2.6.20 (Ubuntu devel).
>>
>> Here are the compilation options of this particular module (built as 
>> part of EBImage, which generally compiles and works just fine):
>>
>> -------------------------------------------------------------------------- 
>>
>> g++ -I/home/osklyar/R/R-2.5.0-40659/include 
>> -I/home/osklyar/R/R-2.5.0-40659/include  -I/usr/local/include 
>> -DUSE_GTK -DGLIB_GETTEXT -I/usr/include/gtk-2.0 
>> -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo 
>> -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 
>> -I/usr/lib/glib-2.0/include   -Wall -g -O2 -Wall -pthread 
>> -I/usr/include -O2 -g -O2 -g  -fpic  -O2 -g  -c filters_watershed.cpp 
>> -o filters_watershed.o
>> -------------------------------------------------------------------------- 
>>
>> And the linker:
>> -------------------------------------------------------------------------- 
>>
>> g++ -shared -L/usr/local/lib64 -o EBImage.so colors.o conversions.o 
>> display.o filters_distmap.o filters_magick.o filters_morph.o 
>> filters_propagate.o filters_thresh.o filters_watershed.o init.o io.o 
>> object_counting.o tools.o -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 
>> -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lfontconfig -lXext -lXrender 
>> -lXinerama -lXi -lXrandr -lXcursor -lXfixes -lpango-1.0 -lcairo -lX11 
>> -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0   -L/usr/lib 
>> -L/usr/X11R6/lib -lfreetype -lz -L/usr/lib -lMagick -llcms -ltiff 
>> -lfreetype -ljasper -ljpeg -lpng -lXext -lSM -lICE -lX11 -lbz2 -lxml2 
>> -lz -lpthread -lm -lpthread
>> -------------------------------------------------------------------------- 
>>
>>
>> It could be I am missing something totally simple and therefore get 
>> these errors, but I cannot identify what.
>>
>> Thanks for help,
>> Oleg
>>
>> -----------------------------------------
>> // common.h also includes R includes:
>> // #include <R.h>
>> // #include <Rdefines.h>
>> // #include <R_ext/Error.h>
>>
>> #include "common.h"
>>
>> #include <queue>
>>
>> using namespace std;
>>
>> struct Pixel {
>>      int x, y;
>>      double intens;
>>      /* the code will also fail with the same segfault if I remove all
>>       * the constructors here and use the commented block below instead
>>       * of pq.push( Pixel(i, j, val) */
>>      Pixel() {x = 0; y = 0; intens = 0; };
>>      Pixel(const Pixel& px) { x = px.x; y = px.y; intens = px.intens; };
>>      Pixel(int i, int j, double val): x(i), y(j), intens(val) {};
>> };
>>
>> bool operator < (const Pixel & a, const Pixel & b) {
>>      return a.intens < b.intens;
>> };
>>
>> typedef priority_queue<Pixel> PixelPrQueue;
>>
>> SEXP
>> lib_filterInvWS (SEXP x) {
>>      SEXP res;
>>      int i, j, index;
>>      double val;
>>      PixelPrQueue pq;
>>
>>      int nx = INTEGER ( GET_DIM(x) )[0];
>>      int ny = INTEGER ( GET_DIM(x) )[1];
>>      int nz = INTEGER ( GET_DIM(x) )[2];
>>      int nprotect = 0;
>>
>>      PROTECT ( res = Rf_duplicate(x) );
>>      nprotect++;
>>
>>      // Pixel px;
>>      for (int im = 0; im < nz; im++ ) {
>>          double * src = &( REAL(x)[ im * nx * ny ] );
>>          double * tgt = &( REAL(res)[ im * nx * ny ] );
>>
>>          for ( j = 0; j < ny; j++ )
>>              for ( i = 0; i < nx; i++ ) {
>>                  index = i + nx * j;
>>                  val = src[ index ];
>>                  if ( val > BG ) {
>>                      tgt[ index ] = -1;
>>                      // px.x = i; px.y = j; px.intens = val; pq.push(px);
>>                      pq.push( Pixel(i, j, val) );
>>                      continue;
>>                  }
>>                  tgt[ index ] = BG;
>>              }
>>      }
>>
>>      /* my main code was here, but deleted for debug */
>>
>>      UNPROTECT (nprotect);
>>      return res;
>> }
>>
>>
>>
>>

-- 
Dr Oleg Sklyar * EBI/EMBL, Cambridge CB10 1SD, England * +44-1223-494466



More information about the R-help mailing list