On Thu, Apr 4, 2013 at 12:10 PM, Robin Girard <robin.gir...@mines-paristech.fr> wrote: > but when I do > > res=new("Rcpp_vector_Of_father",1:10) > res[[1]]$WhoAmI() > res[[0]]$WhoAmI() > > rm(res) > gc() > > that crashes with gc()
Dear Robin, I realize you did not ask for book suggestions, but a gentle walk through all these C++ issues (Slicing, constructors/destructors, and the joy of pointers) is contained in Koenig & Moo's "Accelerated C++: practical programming by example." Sincerely, Krzysztof > R. > > > > ----- Mail original ----- > De: "Robin Girard" <robin.gir...@mines-paristech.fr> > À: "Romain Francois" <rom...@r-enthusiasts.com> > Cc: rcpp-devel@lists.r-forge.r-project.org > Envoyé: Jeudi 4 Avril 2013 18:08:50 > Objet: Re: [Rcpp-devel] Module with vector of a class with inheritance, how > to avoid slicing > > that works.... indeed :) > R. > > > ----- Mail original ----- > De: "Romain Francois" <rom...@r-enthusiasts.com> > À: "Robin Girard" <robin.gir...@mines-paristech.fr> > Cc: rcpp-devel@lists.r-forge.r-project.org > Envoyé: Jeudi 4 Avril 2013 17:58:42 > Objet: Re: [Rcpp-devel] Module with vector of a class with inheritance, how > to avoid slicing > > Le 04/04/13 17:34, Robin Girard a écrit : >> Thanks a lot Romain ! you're amazingly fast and furious (got my seatbelt). >> I'll definitely buy the book. >> >> That works on my example, I confirm (I had a side problem with using _t >> which I removed but don't see where this comes from, my side for sure). Now >> I'm trying to implement it on my "real world" case and I fear that memory >> management with this solution might poses a small problems. >> >> Continuing with our example assume the children class has a field "value_" >> of type double >> >> class children1 : public father >> { >> public: >> double value_ >> ~children1(){}; >> children1(){}; >> children1(double value) : value_(value){}; >> children1(children1 const & x){}; >> virtual void WhoAmI() const{ >> Rcout<<"son1"<<endl; >> }; >> }; >> >> and one want to create a constructor (in the class vector_Of_father) for a >> huge vector of children with a NumericVector as input (one value of the >> vector for one children in the vector) >> >> this will require a loop in c++ and my first try could have been >> >> vector_Of_father(Rcpp::NumericVector vec) : MyfatherList_(vec.size()) >> { >> Rcpp::NumericVector::iterator MyNumericVector_iterator=vec.begin(); >> int i=0; >> while ( MyNumericVector_iterator!=vec.end()) >> { >> children1 *tmp=Calloc(1,children1); // >> tmp->value_=*MyNumericVector_iterator; >> MyfatherList_[i]=tmp; >> ++MyNumericVector_iterator; i++; >> } >> }; >> and I would felt guilty not doing that: >> ~vector_Of_father() >> { >> std::vector<father*>::iterator it=MyfatherList_.begin(); >> while (it!=MyfatherList_.end()){ >> Free(*it); >> ++it; >> } >> }; >> >> but that would clearly be against the spirit of Rcpp, I know, and for sure I >> would not dare to do that (OK, I admit, I tryed and this gave me a leak, >> (all I deserve ?) ) >> >> is there a possibility to convert this into something less intrusive in term >> of memory allocation ? >> I know that's not a big problem since I can do the (big) loop in R... but >> loops in R are like uses of Calloc with Rcpp no ? they are possible but if >> we can avoid them ... > > I would just use new and delete, and likely combine this with some STL > ness to make nicer looking code. Something like this perhaps: > > children* new_children1( double x){ > return new children1( x ) ; > } > > vector_Of_father(Rcpp::NumericVector vec) : MyfatherList_(vec.size()){ > std::transform( vec.begin(), vec.end(), MyfatherList_.begin(), > new_children ) ; > } > > > Same for the destructor: > > template<typename T> > void deleter( T* ptr ){ delete ptr; } > > ~vector_Of_father() { > std::for_each( MyfatherList_.begin(), MyfatherList_.end(), > deleter<father> ) ; > }; > > Of course, with C++11 you could use lambdas instead of the new_children1 > and deleter functions, but that's another story. > > > > Now, this design implies that the vector_Of_father class is repsonsible > for the memory of its pointers. That's fine. But you need to keep this > in mind for when you do stuff with the class, e.g. when you assign an > element to the vector, make sure you delete the previous one, etc ... > > Romain > > >> ----- Mail original ----- >> De: "Romain Francois" <rom...@r-enthusiasts.com> >> À: rcpp-devel@lists.r-forge.r-project.org >> Cc: "Robin Girard" <robin.gir...@mines-paristech.fr> >> Envoyé: Mercredi 3 Avril 2013 22:12:48 >> Objet: Re: [Rcpp-devel] Module with vector of a class with inheritance, how >> to avoid slicing >> >> Hi, >> >> Fasten your seatbelts. >> >> First, the problem is definitely object slicing. The best resource I >> know about to explain it is a chapter of Scott Meyers "Effective C++". >> Robin, I would highly recommend that you get it. Specially considering >> that you are willing to get your hands dirty. >> >> Anyway, I would suggest that your MyfatherList_ is a vector of father >> pointers: >> >> std::vector<father*> MyfatherList_; >> >> if you use any kind of object, even smart pointers, you'll get slicing. >> >> >> Then, you need to have a virtual destructor on the father class and make >> the WhoAmI methods virtual. This is how you do inheritance in C++. >> >> class father >> { >> public: >> virtual ~father(){}; >> father(){}; >> father(father const & x) {}; >> virtual void WhoAmI() const{ >> Rcout<<"father"<<endl; >> }; >> }; >> >> class children1_t : public father >> { >> >> public: >> ~children1_t(){}; >> children1_t(){}; >> children1_t(children1_t const & x){}; >> virtual void WhoAmI() const{ >> Rcout<<"son1"<<endl; >> }; >> }; >> >> This is very basic C++ inheritance stuff. >> >> >> >> The vector class looks like this: >> >> class vector_Of_father { >> >> public: >> std::vector<father*> MyfatherList_; >> ~vector_Of_father(){}; >> vector_Of_father() : MyfatherList_(){}; >> >> father* vec_get( int i) { return MyfatherList_.at(i); }; >> >> void WhoAmI(int i) const { >> MyfatherList_[i]->WhoAmI(); >> }; >> int size(){ return(MyfatherList_.size()); }; >> >> void push_back(object<father> func){ >> MyfatherList_.push_back(func); >> }; >> >> }; >> >> Some comments. >> - As I said above, you are storing a vector of pointers. >> - that makes the implementation of WhoAmI, size simple. >> - for get_vec, you can just return a pointer to a father. We support this. >> - for push_back, you need to use object<father>, that is just a >> disguised pointer. just using father* would require declaring how to >> handle it. We don't support this yet (for some definition of yet). >> Anyway, you can just see object<T> as T* >> >> >> Now the module code. >> >> RCPP_MODULE(mod_example2){ >> >> class_<father>( "father" ) >> .constructor() >> .method("WhoAmI",&father::WhoAmI) >> ; >> >> class_<children1_t>( "children1_t" ) >> .derives<father>("father" ) >> .constructor() >> ; >> >> class_<children2_t>( "children2_t" ) >> .derives<father>("father" ) >> .constructor() >> ; >> >> class_<vector_Of_father>( "vector_Of_father") >> .constructor() >> .method( "size", &vector_Of_father::size) >> .method( "WhoAmI",&vector_Of_father::WhoAmI ) >> .method( "push_back", &vector_Of_father::push_back ) >> .method("[[",&vector_Of_father::vec_get) >> ; >> >> } >> >> That's it. You don't need to redefine WhoAmI for children classes. The >> .derives makes it for you. >> >> And with this: >> >> res <- new( vector_Of_father ) >> res$push_back(new( father )) >> res$push_back(new( children1_t )) >> res$push_back(new( children2_t )) >> res$WhoAmI(2) >> res$WhoAmI(1) >> res$WhoAmI(0) >> res[[2]]$WhoAmI() >> res[[1]]$WhoAmI() >> res[[0]]$WhoAmI() >> >> I do get: >> >> son2 >> son1 >> father >> son2 >> son1 >> father >> >> >> >> >> Here is the full code of the .cpp file: >> >> #include <Rcpp.h> >> >> using namespace std; >> using namespace Rcpp; >> >> class father ; >> class children1_t; >> class children2_t ; >> class vector_Of_father; >> >> RCPP_EXPOSED_CLASS(father) >> RCPP_EXPOSED_CLASS(children1_t) >> RCPP_EXPOSED_CLASS(children2_t) >> RCPP_EXPOSED_CLASS(vector_Of_father) >> >> class father >> { >> public: >> virtual ~father(){}; >> father(){}; >> father(father const & x) {}; >> virtual void WhoAmI() const{ >> Rcout<<"father"<<endl; >> }; >> }; >> >> class children1_t : public father >> { >> >> public: >> ~children1_t(){}; >> children1_t(){}; >> children1_t(children1_t const & x){}; >> virtual void WhoAmI() const{ >> Rcout<<"son1"<<endl; >> }; >> }; >> >> class children2_t : public father >> { >> public: >> ~children2_t(){}; >> children2_t(){}; >> children2_t(children2_t const & x){}; >> virtual void WhoAmI() const{ >> Rcout<<"son2"<<endl; >> }; >> }; >> >> >> class vector_Of_father { >> >> public: >> std::vector<father*> MyfatherList_; >> ~vector_Of_father(){}; >> vector_Of_father() : MyfatherList_(){}; >> >> father* vec_get( int i) { return MyfatherList_.at(i); }; >> >> void WhoAmI(int i) const { >> MyfatherList_[i]->WhoAmI(); >> }; >> int size(){ return(MyfatherList_.size()); }; >> >> void push_back(object<father> func){ >> MyfatherList_.push_back(func); >> }; >> >> }; >> >> >> RCPP_MODULE(mod_example2){ >> >> class_<father>( "father" ) >> .constructor() >> .method("WhoAmI",&father::WhoAmI) >> ; >> >> class_<children1_t>( "children1_t" ) >> .derives<father>("father" ) >> .constructor() >> ; >> >> class_<children2_t>( "children2_t" ) >> .derives<father>("father" ) >> .constructor() >> ; >> >> class_<vector_Of_father>( "vector_Of_father") >> .constructor() >> .method( "size", &vector_Of_father::size) >> .method( "WhoAmI",&vector_Of_father::WhoAmI ) >> .method( "push_back", &vector_Of_father::push_back ) >> .method("[[",&vector_Of_father::vec_get) >> ; >> >> } >> >> Romain >> >> >> Le 03/04/13 18:43, Robin Girard a écrit : >>> I am still working on my vector of a class father with inheritance >>> (polymorphic subclasses ?). I created an exemple below that works fine but >>> I face the known problem of "slicing" as named here : >>> http://stackoverflow.com/questions/10154977/c-vector-with-inheritance and >>> fail to implement the proposed solution. >>> >>> I have 2 tried 2 things and ended up with 2 questions: >>> >>> Question 1 - I tryed the solution proposed in the link with make_shared >>> and shared_ptr. I had to add PKG_CXXFLAGS=-g -std=c++0x since my MinGW >>> compiler did not find any -std=c++11. I got no compilation error but when >>> I run the code it slices my children class : >>> >>>> res=new("Rcpp_vector_Of_father") >>>> res$push_back(new("Rcpp_father")) >>>> res$push_back_children1_t(new("Rcpp_children1_t")) >>>> res$WhoAmI(1) >>> father >>>> res$WhoAmI(0) >>> father >>>> >>>> res[[1]]$WhoAmI() >>> father >>>> res[[0]]$WhoAmI() >>> father >>> >>> >>> Question 2 - I tryed a solution with XPtr (although I'm not sure how this >>> works) and got the following error at the module compilation >>> example_mod_consumption.cpp: In member function 'void >>> vector_Of_father::push_back_children1_t(children1_t)': >>> example_mod_consumption.cpp:80:53: error: no matching function for call to >>> 'std::vector<Rcpp::XPtr<father> >::push_back(Rcpp::XPtr<children1_t>)' >> >> XPtr<father> has no relationship with XPtr<children1_t>. They are >> independant classes generated by the XPtr template class. They don't >> know about the inheritance. >> >>> below are the code for the two approach and at the end the code of the >>> module. >>> >>> >>> >>> -------------------- Solution with XPtr >>> >>> #include <Rcpp.h> >>> >>> using namespace std; >>> using namespace Rcpp; >>> >>> class father ; >>> class children1_t; >>> class children2_t ; >>> class vector_Of_father; >>> >>> RCPP_EXPOSED_CLASS(father) >>> RCPP_EXPOSED_CLASS(children1_t) >>> RCPP_EXPOSED_CLASS(children2_t) >>> RCPP_EXPOSED_CLASS(vector_Of_father) >>> >>> class father >>> { >>> public: >>> ~father(){}; >>> father(){}; >>> father(father const & x) {}; >>> void WhoAmI() const{ >>> Rcout<<"father"<<endl; >>> }; >>> }; >>> >>> class children1_t : public father >>> { >>> >>> public: >>> ~children1_t(){}; >>> children1_t(){}; >>> children1_t(children1_t const & x){}; >>> void WhoAmI() const{ >>> Rcout<<"son1"<<endl; >>> }; >>> }; >>> >>> class children2_t : public father >>> { >>> public: >>> ~children2_t(){}; >>> children2_t(){}; >>> children2_t(children2_t const & x){}; >>> void WhoAmI() const{ >>> Rcout<<"son2"<<endl; >>> }; >>> }; >>> >>> >>> class vector_Of_father { >>> >>> public: >>> std::vector<XPtr<father> > MyfatherList_; >>> //std::vector<shared_ptr<father> > MyfatherList_; >>> ~vector_Of_father(){}; >>> vector_Of_father() : MyfatherList_(){}; >>> father vec_get( int i) { return(*(MyfatherList_.at(i))); }; >>> >>> void WhoAmI(int i) const >>> { >>> MyfatherList_[i]->WhoAmI(); >>> }; >>> int size(){ return(MyfatherList_.size()); }; >>> >>> void push_back(father func){ >>> MyfatherList_.push_back(XPtr<father>(&func)); >>> }; >>> >>> void push_back_children1_t(children1_t func){ >>> MyfatherList_.push_back(XPtr<children1_t>(&func)); >>> }; >>> }; >>> >>> -------------------- Solution with make_shared and shared_ptr >>> >>> only the class vector_of_father is different also #include <memory> is >>> added after Rcpp.h include. >>> >>> class vector_Of_father { >>> >>> public: >>> std::vector<shared_ptr<father> > MyfatherList_; >>> ~vector_Of_father(){}; >>> vector_Of_father() : MyfatherList_(){}; >>> >>> father vec_get( int i) { return(*(MyfatherList_.at(i))); }; >>> >>> void WhoAmI(int i) const >>> { >>> MyfatherList_[i]->WhoAmI(); >>> }; >>> int size(){ return(MyfatherList_.size()); }; >>> >>> >>> void push_back(father func){ >>> MyfatherList_.push_back(make_shared<father>(func)); >>> }; >>> void push_back_children1_t(children1_t func){ >>> MyfatherList_.push_back(make_shared<children1_t>(func)); >>> }; >>> }; >>> >>> >>> >>> -------------- the module code >>> >>> RCPP_MODULE(mod_example2){ >>> using namespace Rcpp; >>> >>> class_<father>( "father" ) >>> //constructors >>> .constructor() >>> .method("WhoAmI",&father::WhoAmI) >>> ; >>> >>> class_<children1_t>( "children1_t" ) >>> .derives<father>("father" ) >>> //constructors >>> .constructor() >>> .method("WhoAmI",&children1_t::WhoAmI) >>> ; >>> >>> class_<children2_t>( "children2_t" ) >>> .derives<father>("father" ) >>> //constructors >>> .constructor() >>> .method("WhoAmI",&children2_t::WhoAmI) >>> ; >>> >>> class_<vector_Of_father>( "vector_Of_father") >>> .constructor() >>> // .constructor<int>() >>> .method( "size", &vector_Of_father::size) >>> // .method("capacity", &cplfunctionvec::capacity,"Return size of >>> allocated storage capacity. Returns the size of the storage space currently >>> allocated for the vector, expressed in terms of elements.") >>> // .method( "max_size", &cplfunctionvec::max_size) >>> .method( "WhoAmI",&vector_Of_father::WhoAmI ) >>> //.method( "test",&vector_Of_father::test ) >>> .method( "push_back", &vector_Of_father::push_back ) >>> >>> .method("push_back_children1_t",&vector_Of_father::push_back_children1_t) >>> // .const_method( "at", &cplfunctionvec::at ) >>> .method("[[",&vector_Of_father::vec_get) >>> // .method("[[<-",&vector_Of_father::vec_set) >>> ; >>> >>> } >>> >>> >>> Dr. Girard Robin >>> Chargé de Recherche >>> >>> MINES-ParisTech / Département Energétique et Procédés / PERSEE / Groupe >>> ERSEI >>> Centre Procédés, Energies Renouvelables et Systèmes Energétiques (PERSEE) >>> Center for Processes, Renewables Energies and Energy Systems >>> Renewable Energies & Smartgrids (ERSEI) >>> >>> 1 Rue Claude Daunesse - CS 10207 - F-06904 Sophia Antipolis Cedex >>> Tel: +33.4.93.67.89.64 (~99), Fax: +33.4.93.95.75.35 >>> e-mail : robin.gir...@mines-paristech.fr >>> >>> web page perso http://www.mines-paristech.fr/Services/Annuaire/&?id=8828 >>> statoverflow : http://stats.stackexchange.com/users/223/robin-girard >>> web page centre PERSEE : http://www.cep.mines-paristech.fr/ >>> linkedin : http://www.linkedin.com/profile/view?id=14907272&trk=tab_pro >> >> > > > -- > Romain Francois > Professional R Enthusiast > +33(0) 6 28 91 30 30 > > R Graph Gallery: http://gallery.r-enthusiasts.com > > blog: http://blog.r-enthusiasts.com > |- http://bit.ly/ZTFLDo : Simpler R help tooltips > `- http://bit.ly/YFsziW : R Help tooltips > > _______________________________________________ > Rcpp-devel mailing list > Rcpp-devel@lists.r-forge.r-project.org > https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel > _______________________________________________ > Rcpp-devel mailing list > Rcpp-devel@lists.r-forge.r-project.org > https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel -- Krzysztof Sakrejda-Leavitt Organismic and Evolutionary Biology University of Massachusetts, Amherst 319 Morrill Science Center South 611 N. Pleasant Street Amherst, MA 01003 work #: 413-325-6555 email: sakre...@cns.umass.edu ----------------------------------------------- _______________________________________________ Rcpp-devel mailing list Rcpp-devel@lists.r-forge.r-project.org https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel