[Rcpp-devel] c++ class as argument in rcpp function (using modules)

Dirk Eddelbuettel edd at debian.org
Sat Dec 24 00:38:22 CET 2011


On 23 December 2011 at 18:16, Yasir Suhail wrote:
| Hi,
| 
| I think I have figured out why we were getting the error. When we call the
| function from R, the type of the instance passed is S4SXP, rather than
| EXTPTRSXP, which is what XPtr(SEXP) expects. 

That's possible.  

| We can, however, use the Rcpp::S4
| (SEXP) constructor to get an S4 object. Are the user defined C++ classes
| derived from Rcpp::S4 classes? 
| 
| I don't know if there is still interest in this, so I don't know if I should
| keep filling your inboxes.

I think there is, but not everybody uses Rcpp modules all that actively so
that you may have a limited audience.

But extending Rcpp modules, and/or documenting it better, is definitely on
the TODO list so you are on the right track.  

Dirk

| Thanks!
| 
| On Thu, Dec 22, 2011 at 9:18 PM, Yasir Suhail <yusuhail at gmail.com> wrote:
| 
|     Hi,
| 
|     Dirk, thanks for uploading the next version, because it does sort of help
|     here. The error now with Rcpp 0.9.8 is "expecting an external pointer" from
|     XPtr on the following very toy example. It has something to do with the
|     type of SEXP in the constructor, but I am not very familiar with the Rcpp
|     internals to be able to figure it out.
| 
|     #include <Rcpp.h>
|     class World {
|     public:
|         World() : msg("hello"){}
|         World(const std::string s) : msg(s){}
|         void set(std::string msg) { this->msg = msg; }
|         std::string greet() const { return msg; }
|         void addMsg(const World w2) {
|             this->msg = this->msg + w2.greet();
|         }
|         World(SEXP x) {
|             Rcpp::XPtr<World> ptr(x);
|             msg = ptr->greet();
|        }
|     private:
|         std::string msg;
|     };
|     RCPP_MODULE(yada){
|             using namespace Rcpp ;
|             class_<World>( "World" )
|                 .constructor()
|                 .constructor<std::string>()
|                     .method( "greet", &World::greet , "get the message"
|     )
|                     .method( "set", &World::set     , "set the
|     message" )
|                     .method( "addMsg", &World::addMsg  , "add the
|     message from another object" );
|     }
| 
|     And then in R:
| 
|     >library(yada)
|     >a <- new(World,"this is a")
|     >b <- new(World,"this is b")
|     >a$addMsg(b)
|     Error in a$addMsg(b) : expecting an external pointer
| 
|     I'd appreciate if someone could shed some light on it.
| 
|     Thanks!
| 
|     On Wed, Dec 21, 2011 at 7:52 PM, Yasir Suhail <yusuhail at gmail.com> wrote:
| 
|         Hi,
| 
|         Other than the approaches mentioned, I can also specialize an as
|         <World>(SEXP) as
| 
|              template <>
|              World as<World>(SEXP x) {
|         Rcpp::XPtr<World> ptr(x);
|         return World(ptr->greet());
|              }
| 
|         However, this also gives segfault at runtime when addMsg is called. The
|         final code, with alternative implementations commented out for
|         experimentation is:
| 
|         #include <RcppCommon.h>
|         #include <string>
|         class World {
|         public:
|             World() : msg("hello"){}
|             World(const std::string s) : msg(s){}
|             void set(std::string msg) { this->msg = msg; }
|             std::string greet() const { return msg; }
|             void addMsg(const World w2) {
|         this->msg = this->msg + w2.greet();
|             }
|         //    World(SEXP x);
|         /*    World(SEXPREC* &w2) {
|         msg = ((World*)w2)->greet();
|             }
|         */
|         private: 
|             std::string msg;
|         };
|         namespace Rcpp{
| 
|         template <> SEXP wrap(const World& object);
|         template <> World as<World>(SEXP x);
|         }
|         #include <Rcpp.h>
| 
| 
|         namespace Rcpp {
|              template <>
|              SEXP wrap( const World& object ){
|                  Language call( "new", Symbol( "World" ), object.greet() )
|         ;
|                  return call.eval() ;
|              }
|              template <>
|              World as<World>(SEXP x) {
|         Rcpp::XPtr<World> ptr(x);
|         return World(ptr->greet());
|              }
|         }
| 
| 
|         /*World::World(SEXP x) {
|         Rcpp::XPtr<World> ptr(x);
|         msg = ptr->greet();
|         }*/
| 
|         //...
| 
|         RCPP_MODULE(yada){
|         using namespace Rcpp ;
|         class_<World>( "World" )
|             // expose the default constructor
|             .constructor()
|                     .constructor<std::string>()
|             .method( "greet", &World::greet , "get the message" )
|         .method( "set", &World::set     , "set the message" )
|         .method( "addMsg", &World::addMsg  , "add the message from another
|         object" );
|         }
| 
|         Then, running with R -d gdb
|         > a <- new(World,"hello ")
|         > b <- new(World,"worlds")
|         > a$greet( )
|         [1] "hello "
|         > a$addMsg( b)
| 
|         Program received signal EXC_BAD_ACCESS, Could not access memory.
|         Reason: KERN_INVALID_ADDRESS at address: 0x0000000011000078
|         0x00000001042032df in std::basic_string<char, std::char_traits<char>,
|         std::allocator<char> >::basic_string ()
|         (gdb) bt
|         #0  0x00000001042032df in std::basic_string<char, std::char_traits
|         <char>, std::allocator<char> >::basic_string ()
|         #1  0x0000000104358b18 in Rcpp::as<World> ()
|         #2  0x000000010435d564 in Rcpp::CppMethod1<World, void,
|         World>::operator() ()
|         #3  0x000000010435eadb in Rcpp::class_<World>::invoke_void ()
|         #4  0x0000000104164670 in CppMethod__invoke_void ()
|         #5  0x00000001000928e9 in do_External ()
|         #6  0x00000001000c4af7 in Rf_eval ()
|         #7  0x00000001000c6d99 in do_begin ()
|         #8  0x00000001000c48af in Rf_eval ()
|         #9  0x00000001000c7cf3 in Rf_applyClosure ()
|         #10 0x00000001000c4778 in Rf_eval ()
|         #11 0x00000001000fed75 in Rf_ReplIteration ()
|         #12 0x00000001000ff021 in R_ReplConsole ()
|         #13 0x00000001000ff590 in run_Rmainloop ()
|         #14 0x0000000100000e8b in main ()
|         (gdb) 
| 
|         Thanks!
| 
|         On Wed, Dec 21, 2011 at 7:41 PM, Darren Cook <darren at dcook.org> wrote:
| 
|             Hello Yasir,
|             Could you post your complete (minimal) code to the list. Then
|             someone
|             might be curious enough to try reproducing the problem.
|            
|             Darren
|            
| 
|             On 2011-12-22 08:29, Yasir Suhail wrote:
|             > Thanks Darren, Douglas, Richard, and Dirk!
|             >
|             > I can compile with the following definitions:
|             >
|             > World(SEXP x) {
|             > Rcpp::XPtr<World> ptr(x);
|             > msg = ptr->msg;
|             > }
| 
|             > ...
| 
| 
|             --
|             Darren Cook, Software Researcher/Developer
| 
|             http://dcook.org/work/ (About me and my work)
|             http://dcook.org/blogs.html (My blogs and articles)
| 
| 
| 
| 
| 
| 
| 
| ----------------------------------------------------------------------
| _______________________________________________
| 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
-- 
"Outside of a dog, a book is a man's best friend. Inside of a dog, it is too
dark to read." -- Groucho Marx


More information about the Rcpp-devel mailing list