[Rcpp-devel] Pointer troubles

Sebastian Weber sebastian.weber at frias.uni-freiburg.de
Wed Aug 3 17:13:19 CEST 2011


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? 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.

Moreover, I saw that basically the whole class_-declaration mechanism boils down to stuff things into XPtr, right? 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...

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