[Rcpp-devel] Pointer troubles

romain at r-enthusiasts.com romain at r-enthusiasts.com
Wed Aug 3 18:30:08 CEST 2011





Le 3 août 2011 à 17:13, Sebastian Weber <sebastian.weber at frias.uni-freiburg.de> a écrit :

> Hi!
> 
> Reading this thread, I hit on some questions which would help me understand Rcpp a lot better.
> 
>> We have the Rcpp::XPtr template class that is parameterized by the class of the pointer, the XPtr object acts as a smart pointer, so can be passed down to whatever C++ function that needs a pointer. It also adds the necessary wrapping so that you can pass the object back to R as an external pointer.
> 
> Hmm, I understand that XPtr is always a "strong" pointer in the sense that XPtr will delete the object once it gets out of scope. Is that right?

Yes 

> If so, how can I get a weak pointer? I.e. tell XPtr to never call a finalizer at all since the ownership is handled at a different spot in my code.

You can register your own finalizer, that does whatever you want, release ressources, etc ...

This is handled by a second template parameter of the XPtr template. 

This was added recently and i sent an email to the list, one month or so ago. 

> Moreover, I saw that basically the whole class_-declaration mechanism boils down to stuff things into XPtr, right?

Yep

> So on the C++ side one has actually pointers to wrapped classes which are held by XPtr. How can I now obtain these pointers and what is the type of the wrapped classes? The problem is that I have to deal with a wrapped class A, but might also fool around with A* in my code...

Not sure yet. I'll mess around and see if i can get a toy example going. 

Romain

> Cheers,
> 
> Sebastian
> 
>> 
>> With the XPtr class, you would write your code something like this:
>> 
>> SEXP getIntPointer(){
>>   int *test = new int; *test = 6;
>> 
>>   XPtr<int> retVal(test) ;
>>   return retVal ;
>> }
>> 
>> SEXP doubleIntPointer(SEXP test){
>>   XPtr<int> test2(test) ;
>>   return wrap( *test2 * 2 ) ;
>> }
>> 
>> You don't need intObjFinalizer because this is the same as the default finalizer that is shipped for free with XPtr:
>> 
>> template <typename T>
>> void standard_delete_finalizer(T* obj){
>>   delete obj ;
>> }
>> 
>> template <typename T, void Finalizer(T*) >
>> void finalizer_wrapper(SEXP p){
>>   if( TYPEOF(p) == EXTPTRSXP ){
>>    T* ptr = (T*) R_ExternalPtrAddr(p) ;
>>    Finalizer(ptr) ;
>>   }
>> }
>> 
>> 
>> You don't need int2SEXP because the XPtr constructor deals with it.
>> 
>> You don't need the SEXP2int because the XPtr dereferences itself to the actual underlying pointer class.
>> 
>> HTH,
>> 
>> Romain
>> 
>> Le 03/08/11 12:13, Willem Ligtenberg a écrit :
>>> Hi Dirk and list,
>>> 
>>> Indeed it might have been a bit too complicated.
>>> I think I have another example, which explains my troubles without
>>> requiring OpenCL.
>>> In this case, I want to return a pointer to an integer value to R and
>>> the double the integer value in another function.
>>> (I know this is stupid to do, but it is a toy example)
>>> 
>>> // Stuff to expose the int to R
>>> static void intObjFinalizer(SEXP ref){
>>>       if(TYPEOF(ref) == EXTPTRSXP){
>>>               int *o = static_cast<int*>  (R_ExternalPtrAddr(ref));
>>>               if (o) delete o;
>>>       }
>>> }
>>> 
>>> SEXP int2EXP(int *o){
>>>       SEXP xp = R_MakeExternalPtr(o, R_NilValue, R_NilValue);
>>>       R_RegisterCFinalizerEx(xp, intObjFinalizer, TRUE);
>>>       return xp;
>>> }
>>> 
>>> int *SEXP2int(SEXP o){
>>>       if(TYPEOF(o) != EXTPTRSXP)
>>>               Rf_error("invalid object");
>>>       return (int*) R_ExternalPtrAddr(o);
>>> }
>>> 
>>> SEXP getIntPointer(){
>>>    int test = 6;
>>>    SEXP retVal = int2EXP(&test);
>>>    std::cout<<  test<<  "\n";
>>>    int test2 = *SEXP2int(retVal);
>>>    std::cout<<  test2<<  "\n";
>>>    return retVal;
>>> }
>>> 
>>> SEXP doubleIntPointer(SEXP test){
>>>    int test2 = *SEXP2int(test);
>>>    std::cout<<  test2;
>>>    return Rcpp::wrap(test2*2);
>>> }
>>> 
>>> By the way, I use a module to expose these functions:
>>> 
>>> RCPP_MODULE(ropencl){
>>>    using namespace Rcpp ;
>>>    function( "getIntPointer"  ,&getIntPointer , "getIntPointer" ) ;
>>>    function( "doubleIntPointer"  ,&doubleIntPointer , "doubleIntPointer" ) ;
>>> }
>>> 
>>> When I now execute getIntPointer() from R, it seems to work fine, both
>>> the initial integer and the value that I get back from
>>> *SEXP2int(retVal); are 6. (Although when I exit R after only this call
>>> I get the following: *** glibc detected *** /usr/lib64/R/bin/exec/R:
>>> free(): invalid pointer: 0x00007fffd1a587cc ***)
>>> 
>>> However, when I now use doubleIntPointer(getIntPointer()) in R, I get
>>> some wrong result (a different value each time I restart R).
>>> 
>>> Does this make it a bit more clear what I want to do, or the problems
>>> that I am facing?
>>> 
>>> Kind regards,
>>> 
>>> Willem
>>> 
>>> On Tue, Aug 2, 2011 at 15:24, Dirk Eddelbuettel<edd at debian.org>  wrote:
>>>> 
>>>> Hi Willem,
>>>> 
>>>> Thanks a pretty long and complicated post.  Could we possibly break it down
>>>> into smaller pieces?
>>>> 
>>>> On 2 August 2011 at 11:45, Willem Ligtenberg wrote:
>>>> | Hi,
>>>> |
>>>> | I am trying to wrap around OpenCL.
>>>> | But I am running into some problems when I try to return pointers to
>>>> | R. Later I want to be able to use these pointers in other c functions.
>>>> | As an example I have the following code:
>>>> |
>>>> | #include "createContext.h"
>>>> | #include<CL/opencl.h>
>>>> | #include<Rcpp.h>
>>>> |
>>>> | // Stuff to expose the cl_platform_id to R
>>>> | static void cl_platform_idObjFinalizer(SEXP ref){
>>>> |       if(TYPEOF(ref) == EXTPTRSXP){
>>>> |               cl_platform_id *o = static_cast<cl_platform_id*>  (R_ExternalPtrAddr(ref));
>>>> |               if (o) delete o;
>>>> |       }
>>>> | }
>>>> |
>>>> | SEXP cl_platform_id2EXP(cl_platform_id *o){
>>>> |       SEXP xp = R_MakeExternalPtr(o, R_NilValue, R_NilValue);
>>>> |       R_RegisterCFinalizerEx(xp, cl_platform_idObjFinalizer, TRUE);
>>>> |       return xp;
>>>> | }
>>>> |
>>>> | cl_platform_id *SEXP2cl_platform_id(SEXP o){
>>>> |       if(TYPEOF(o) != EXTPTRSXP)
>>>> |               Rf_error("invalid object");
>>>> |       return (cl_platform_id*) R_ExternalPtrAddr(o);
>>>> | }
>>>> |
>>>> | This bit I have found posted on this mailing list earlier.
>>>> | This is to expose a pointer to a cl_platform_id object in memory (and
>>>> | this should also take care of the clean up).
>>>> |
>>>> | Now I have the following method to get a list of platform_ids:
>>>> |
>>>> | SEXP getPlatformIDs(){
>>>> |       //returns a list of platform ids
>>>> |       cl_uint num_platforms = 0;
>>>> |       clGetPlatformIDs(0, 0,&num_platforms);
>>>> |       std::vector<cl_platform_id>  platforms(num_platforms);
>>>> |       clGetPlatformIDs(num_platforms, platforms.empty() ? NULL :
>>>> |&platforms.front(),&num_platforms);
>>>> |       //for each platform in platforms add its pointer to the return list
>>>> |       Rcpp::List result(platforms.size());
>>>> |       for (int i=0; i<platforms.size(); i++){
>>>> |         cl_platform_id tempPlatformID = platforms[i];
>>>> |               result[i] = cl_platform_id2EXP(&tempPlatformID);
>>>> |       }
>>>> |       return result;
>>>> | }
>>>> |
>>>> | And I want to get the name of the platform as follows:
>>>> |
>>>> | SEXP getPlatformName(SEXP sPlatformID){
>>>> |     char cBuffer[1024];
>>>> |     cl_platform_id platformID = *SEXP2cl_platform_id(sPlatformID);
>>>> |     clGetPlatformInfo (platformID, CL_PLATFORM_NAME, sizeof(cBuffer),
>>>> | cBuffer, NULL);
>>>> |     Rcpp::CharacterVector ab(1);
>>>> |     ab[0] = cBuffer;
>>>> |     return ab;
>>>> 
>>>> You could use wrap() on std::string or char* if you just want to return a
>>>> single string. No need for a CharacterVector of size 1.
>>>> 
>>>> | }
>>>> |
>>>> | The whole lot compiles, but gives a runtime error. When I try the
>>>> | following in R:
>>>> | library(ROpenCL)
>>>> | platformIDs<- getPlatformIDs()
>>>> | print(getPlatformName(platformIDs[[1]]))
>>>> |
>>>> | *** caught segfault ***
>>>> | address 0x51, cause 'memory not mapped'
>>>> |
>>>> | Now when I put all this together in one method which just returns the
>>>> | platform name, it works:
>>>> |
>>>> | SEXP getPlatformIDs2(){
>>>> |       //returns a list of platform ids
>>>> |       cl_uint num_platforms = 0;
>>>> |       clGetPlatformIDs(0, 0,&num_platforms);
>>>> |       std::vector<cl_platform_id>  platforms(num_platforms);
>>>> |       clGetPlatformIDs(num_platforms, platforms.empty() ? NULL :
>>>> |&platforms.front(),&num_platforms);
>>>> |       char cBuffer[1024];
>>>> |     clGetPlatformInfo (platforms[0], CL_PLATFORM_NAME,
>>>> | sizeof(cBuffer), cBuffer, NULL);
>>>> |     Rcpp::CharacterVector ab(1);
>>>> |     ab[0] = cBuffer;
>>>> |     return ab;
>>>> | }
>>>> |
>>>> | This results in:
>>>> | getPlatformIDs2()
>>>> | [1] "NVIDIA CUDA"
>>>> |
>>>> | Could someone check if I am taking the pointer to and from R in the correct way?
>>>> 
>>>> I can't as I do not know the OpenCL API.
>>>> 
>>>> One thought is that maybe you do not you really need external pointers as you
>>>> are just copying IDs around. Can you simplify what you are trying to do?
>>>> 
>>>> Cheers, Dirk
>>>> 
>>>> --
>>>> Gauss once played himself in a zero-sum game and won $50.
>>>>                     -- #11 at http://www.gaussfacts.com
>>>> 
>>> _______________________________________________
>>> Rcpp-devel mailing list
>>> Rcpp-devel at lists.r-forge.r-project.org
>>> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
>>> 
>> 
>> 
>> -- 
>> Romain Francois
>> Professional R Enthusiast
>> +33(0) 6 28 91 30 30
>> http://romainfrancois.blog.free.fr
>> http://romain-francois.com
>> |- http://bit.ly/lJoWbH : Montpellier Comédie Club - Juin 2011
>> |- http://bit.ly/kaSV6U : Stand up set at Up The Creek
>> `- http://bit.ly/hdKhCy : Rcpp article in JSS
>> 
>> 
>> _______________________________________________
>> Rcpp-devel mailing list
>> Rcpp-devel at lists.r-forge.r-project.org
>> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
> 
> -- 
> Sebastian Weber
> Group of Cell Communication and Control
> Freiburg Institute for Advanced Studies - FRIAS
> School of Life Sciences - LIFENET
> Albert-Ludwigs-Universität Freiburg
> Albertstr. 19
> 79104 Freiburg
> T.: +49-761-203-97237
> Fax:+49-761-203-97334
> 


More information about the Rcpp-devel mailing list