2017-02-08 3 views
0

У меня есть класс C++, который хранит необработанный указатель на объекты своего рода в качестве переменной-члена. Класс отображается через Rcpp-модули в R. Я хотел бы вернуть ссылку на переменную-член через свойство. Однако кажется, что копия возвращается.Модули Rcpp: Возвращение ссылки на объект-переменную C++-объект на R

Это также относится и к другим случаям, когда переменные объекты разных членов возвращаются к R.

Минимального воспроизводимый пример

создать новый пакет скелета с помощью Rcpp::Rcpp.package.skeleton('testmod', module = TRUE) и добавил свой собственный класс Foo, подвергая его к R. Пример можно найти here на github.

Содержание Src/foo.cpp:

#include <Rcpp.h> 

class Foo; 
RCPP_EXPOSED_CLASS(Foo) 

class Foo 
{ 
    public: 
    Foo(): 
     ancestor_ptr(NULL){} 
    Foo(const Foo& ancestor): 
     ancestor_ptr(&ancestor){} 

    const Foo& get_ancestor() {return *ancestor_ptr;} 

    const Foo* ancestor_ptr; 
}; 


RCPP_MODULE(mymodule){ 
    using namespace Rcpp ; 

    class_<Foo>("Foo") 
    .default_constructor() 
    .constructor<const Foo&>() 
    .property("ancestor", &Foo::get_ancestor) 
    ; 
} 

Тестирование в R сессии дает мне:

>library(testmod) 
>a <- new(Foo) 
>b <- new(Foo, a) 
>a 
C++ object <0x1c57108> of class 'Foo' <0x22d78b0> 
>b$ancestor 
C++ object <0x1f8ffa0> of class 'Foo' <0x22d78b0> 

Так 0x1c57108 != 0x1f8ffa0, и я проверил с вспомогательными функциями, не показали, что 0x1c57108 на самом деле адрес объекта a.

EDIT Я только что проверил с помощью UUID переменной-члена и пользовательского конструктора копии, которые делаются на самом деле копии объектов-членов.

+0

Я не уверен, что делаю то же самое предположение, что и вам, что это должно сработать. Более простой подход может быть первым классом C++ с указателями на другие экземпляры. Вы сами управляете этой памятью, которая представляет собой простое приложение на C++. Затем вы используете один класс на основе Rcpp для доступа к этой новой структуре. –

+0

@DirkEddelbuettel Итак, вы имеете в виду, что это может быть невозможно? Мне интересно, в каком месте сделана копия. С вашим предложением вы хотите использовать класс контроллера, который функционирует как дескриптор для управления всем приложением из R? Тем не менее, возвращение ссылок было бы действительно хорошей вещью, поскольку это позволило бы реализовать/прототипировать некоторые функции в R. – NoBackingDown

ответ

4

Что происходит, так это то, что модули не могут обрабатывать возвращаемые ссылки, поэтому при вызове get_ancestor выполняется копия.

Рассмотрим эту расширенную версию кода:

#include <Rcpp.h> 

class Foo; 
RCPP_EXPOSED_CLASS(Foo) 

    class Foo 
    { 
    public: 
    Foo(): 
    ancestor_ptr(NULL){} 
    Foo(const Foo& ancestor): 
     ancestor_ptr(&ancestor) 
    { 
     Rprintf("Foo(const Foo&)\n") ; 
    } 

    const Foo& get_ancestor() {return *ancestor_ptr;} 
    const Foo* ancestor_ptr; 

    void print_ptr(){ 
     Rprintf("ptr = %p\n", this) ; 
    } 

    void print_ancestor_ptr(){ 
     Rprintf("ptr = %p\n", ancestor_ptr) ; 
    } 

    }; 


RCPP_MODULE(mymodule){ 
    using namespace Rcpp ; 

    class_<Foo>("Foo") 
    .default_constructor() 
    .constructor<const Foo&>() 
    .property("ancestor", &Foo::get_ancestor) 
    .method("print_ptr", &Foo::print_ptr) 
    .method("print_ancestor_ptr", &Foo::print_ancestor_ptr) 
    ; 
} 

Копия сделана при вызове конструктора копирования, который прекрасно и что вы имеете в виду, чтобы случиться:

> a <- new(Foo) 
> b <- new(Foo, a) 
Foo(const Foo&) 

Но один также, когда вы звоните get_ancestor:

> b$ancestor 
Foo(const Foo&) 
C++ object <0x10204ee00> of class 'Foo' <0x10207c7c0> 

Однако в b Вы действительно храните правильный указатель:

> a$print_ptr() 
ptr = 0x113278820 
> b$print_ancestor_ptr() 
ptr = 0x113278820 
+0

Спасибо за ваш четкий ответ! Похоже, что нет другого способа, чем перепроектировать мое приложение для работы исключительно на стороне C++. – NoBackingDown

+0

Действительно, не доработав модули, чтобы они правильно обрабатывали ссылки. 'Boost.Python' делает так, что это возможно. –

+0

Это было бы потрясающе. Есть ли какие-либо реалистичные ожидания, что эта функция будет добавлена ​​в ближайшем будущем? – NoBackingDown