Last active
August 29, 2015 13:56
-
-
Save Thell/9286048 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*** | |
* | |
* Scenario: | |
* | |
* You desire to use RCPP_EXPOSE_CLASS on a class and it needs to store | |
* a pointer to somewhere in a constructor initialized container either | |
* using the default initializer list or from within the constructor. | |
* | |
* Problem: | |
* | |
* There is a behavior difference between the copy constructor behavior of | |
* the RCPP:: containers (IntegerVector) and the std:: containers where-by | |
* the rcpp versions re-use memory and the std:: versions are moved. | |
* | |
* Reproduction: | |
* | |
* Two classes, identical except for the underlying storage container types. | |
* - ClassA using IntegerVector. | |
* - ClassB using std::vector< int >. | |
* | |
* | |
* - Rcpp::sourceCpp('rcpp_issue.cpp') | |
* | |
* - Note that both the IntegerVector and std::vector classes have the copy | |
* constructor called when used via R. My guess is that because it is already | |
* in R protected/managed memory space it is re-usable... but honesly I know | |
* nothing about that. | |
* | |
* | |
* Fix for end-users :: provide a copy constructor. | |
* Fix for rcpp :: ?? | |
* | |
*/ | |
// [[Rcpp::plugins("cpp11")]] | |
#include <ostream> | |
#include <iterator> | |
#include <typeinfo> | |
#include <typeindex> | |
#include <unordered_map> | |
#include <string> | |
#include <memory> | |
#include <RcppCommon.h> | |
class ClassA; | |
RCPP_EXPOSED_CLASS(ClassA) | |
class ClassB; | |
RCPP_EXPOSED_CLASS(ClassB) | |
#include <Rcpp.h> | |
using namespace Rcpp; | |
void print_ptrs(const int * p_vec, std::type_index vec_info, | |
const int * p_iter, std::type_index iter_info ) | |
{ | |
std::unordered_map< std::type_index, std::string > type_names; | |
type_names[std::type_index(typeid(IntegerVector))] = "IntegerVector"; | |
type_names[std::type_index(typeid(IntegerVector::iterator))] = | |
"IntegerVector::iterator"; | |
type_names[std::type_index(typeid(std::vector<int>))] = "std::vector"; | |
type_names[std::type_index(typeid(std::vector<int>::iterator))] = | |
"std::vector iterator"; | |
std::cout << " vec.begin() addr: " << p_vec << " [" | |
<< type_names[std::type_index(vec_info)] << "]" << std::endl | |
<< " iter addr: " << p_iter << " [" | |
<< type_names[std::type_index(iter_info)] << "]" << std::endl; | |
} | |
class ClassA { | |
public: | |
IntegerVector vec; | |
IntegerVector::iterator iter; | |
ClassA(int len) : vec(len), iter( vec.begin() ) | |
{ | |
std::cout << "Ctor ::" << std::endl; | |
std::cout << " vec type: " << typeid(vec).name() << std::endl | |
<< " iter type: " << typeid(iter).name() << std::endl | |
<< std::endl; | |
print_ptrs( std::addressof(*vec.begin()), std::type_index(typeid(vec)), | |
std::addressof(*iter), std::type_index(typeid(iter)) ); | |
} | |
ClassA( const ClassA& other ) : vec(other.vec), iter(other.iter) { | |
std::cout << "Copy Ctor ::" << std::endl; | |
std::cout << "--- other ---" << std::endl; | |
print_ptrs( std::addressof(*other.vec.begin()), std::type_index(typeid(other.vec)), | |
std::addressof(*other.iter), std::type_index(typeid(other.iter)) ); | |
std::cout << "--- this ---" << std::endl; | |
print_ptrs( std::addressof(*vec.begin()), std::type_index(typeid(vec)), | |
std::addressof(*iter), std::type_index(typeid(iter)) ); | |
} | |
~ClassA() { | |
std::cout << "Dtor" << std::endl; | |
} | |
}; // end class: ClassA | |
class ClassB { | |
public: | |
std::vector< int > vec; | |
std::vector< int >::iterator iter; | |
ClassB(int len) : vec(len), iter( vec.begin() ) | |
{ | |
std::cout << "Ctor ::" << std::endl; | |
std::cout << " vec type: " << typeid(vec).name() << std::endl | |
<< " iter type: " << typeid(iter).name() << std::endl | |
<< std::endl; | |
print_ptrs( std::addressof(*vec.begin()), std::type_index(typeid(vec)), | |
std::addressof(*iter), std::type_index(typeid(iter)) ); | |
} | |
ClassB( const ClassB& other ) : vec(other.vec), iter(other.iter) { | |
std::cout << "Copy Ctor ::" << std::endl; | |
std::cout << "--- other ---" << std::endl; | |
print_ptrs( std::addressof(*other.vec.begin()), std::type_index(typeid(other.vec)), | |
std::addressof(*other.iter), std::type_index(typeid(other.iter)) ); | |
std::cout << "--- this ---" << std::endl; | |
print_ptrs( std::addressof(*vec.begin()), std::type_index(typeid(vec)), | |
std::addressof(*iter), std::type_index(typeid(iter)) ); | |
} | |
~ClassB() { | |
std::cout << "Dtor" << std::endl; | |
} | |
}; // end class: ClassB | |
ClassA make_ClassA( int n ) { return ClassA(n); } | |
RCPP_MODULE(ClassA){ | |
class_< ClassA >("ClassA") | |
.constructor< int >() | |
; | |
function( "make_ClassA", &make_ClassA ); | |
} | |
ClassB make_ClassB( int n ) { return ClassB(n); } | |
RCPP_MODULE(ClassB){ | |
class_< ClassB >("ClassB") | |
.constructor< int >() | |
; | |
function( "make_ClassB", &make_ClassB ); | |
} | |
// [[Rcpp::export]] | |
void rcpp_behaviorA(int n) | |
{ | |
auto bi = ClassA(n); | |
} | |
// [[Rcpp::export]] | |
void rcpp_behaviorB(int n) | |
{ | |
auto bi = ClassB(n); | |
} | |
/*** R | |
############ RCPP ################# | |
## ClassA and ClassB behave the same | |
# ClassA behavior in Rcpp function. | |
rcpp_behaviorA(1) | |
# ClassB behavior in Rcpp function. | |
rcpp_behaviorB(1) | |
############# R ################### | |
## ClassB gets a change of address. | |
bi <- make_ClassA(1) | |
rm(bi) | |
rm(ClassA) | |
# Exposed ClassB behavior in R. | |
bi <- make_ClassB(1) | |
rm(bi) | |
rm(ClassB) | |
gc() # Dtor | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment