2016-03-23 9 views
5

Я пытаюсь сделать interop с C++ и D. И то, что я нашел сегодня, действительно пугает мой разум: объекты не передаются правильно в моей программе.Как передать объект из D в C++?

Лучше показать пример.

У меня есть библиотека C++, которую я компилирую в объектный файл и программу D, которую я связываю с моей библиотекой и запускаю.

Вот они:

#include <stdio.h> 

class Color 
{ 
public: 
    Color(unsigned int _r, unsigned int _g, unsigned int _b) : r(_r), g(_g), b(_b) {} 

    unsigned int r, g, b; 
}; 

class Printer 
{ 
public: 
    Printer() {} 
    ~Printer() {} 
    static Printer* getInstance(); 
    void print(Color *c); 
}; 

Printer* Printer::getInstance() 
{ 
    return new Printer(); 
} 

void Printer::print(Color *c) 
{ 
    printf("(%d, %d, %d)\n", c->r, c->g, c->b); 
} 

И программа D:

import std.stdio; 

extern(C++) 
{ 
    class Color 
    { 
    uint r, g, b; 

    this(uint _r, uint _g, uint _b) 
    { 
     r = _r; 
     g = _g; 
     b = _b; 
    } 
    } 

    class Printer 
    { 
    @disable this(); 
    static Printer getInstance(); 
    final void print(Color c); 
    } 
} 

void main() 
{ 
    auto printer = Printer.getInstance(); 

    Color c = new Color(42, 7, 19); 

    printer.print(c); 
} 

компилировать их с этими командами:

c++ -c my_core.cpp -o my_core.o 
dmd main.d my_core.o -L-lstdc++ 

Но когда я бегу ./main, я получил странное результаты:

(113244372, 1, 42) 

Что заставило меня думать, что объекты передаются неправильно, просто эксперимент. Во-первых, я побежал мою программу несколько раз, и вот что я увидел:

$ ./main 
(266442332, 1, 42) 
$ ./main 
(234899036, 1, 42) 
$ ./main 
(109475420, 1, 42) 

Таким образом, первый номер, кажется, указатель на блок памяти. И мое шестое чувство в паре с знаниями о сборке заставляет меня думать, что это указатель на переменную this.

И теперь, только, чтобы подтвердить мои данные все еще на месте, и эти цифры не просто случайные те, я добавил еще два поля для моего класса Color:

C++ Lib:

#include <stdio.h> 

class Color 
{ 
public: 
    Color(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) : r(_r), g(_g), b(_b), u(_u), v(_v) {} 

    unsigned int r, g, b, u, v; 
}; 

class Printer 
{ 
public: 
    Printer() {} 
    ~Printer() {} 
    static Printer* getInstance(); 
    void print(Color *c); 
}; 

Printer* Printer::getInstance() 
{ 
    return new Printer(); 
} 

void Printer::print(Color *c) 
{ 
    printf("(%d, %d, %d, %d, %d)\n", c->r, c->g, c->b, c->u, c->v); 
} 

И программа D:

import std.stdio; 

extern(C++) 
{ 
    class Color 
    { 
    this(uint _r, uint _g, uint _b, uint _u, uint _v) 
    { 
     r = _r; 
     g = _g; 
     b = _b; 
     u = _u; 
     v = _v; 
    } 

    uint r, g, b, u, v; 
    } 

    class Printer 
    { 
    @disable this(); 
    static Printer getInstance(); 
    final void print(Color c); 
    } 
} 

void main() 
{ 
    auto printer = Printer.getInstance(); 

    Color c = new Color(42, 7, 19, 499, 727); 

    printer.print(c); 
} 

И выходы:

$ ./main       
(90379876, 1, 42, 7, 19) 
$ ./main 
(79758948, 1, 42, 7, 19) 
$ ./main 
(74901092, 1, 42, 7, 19) 
$ ./main 
(217458276, 1, 42, 7, 19) 
$ ./main 
(238933604, 1, 42, 7, 19) 

Я пробовал скомпилировать мою программу как с компиляторами DMD, так и с LDC, но оба предоставили мне точно такое же поведение.

UPD: Что еще более интересно и (вероятно) указывая, где проблема заключается, является тот факт, объекты, созданные в Lib C++ в настоящее время проходит между D и C++ правильно.

Чтобы доказать это, я создал "фабричный метод" в моем Color классе:

static Color* create(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) { 
    return new Color(_r, _g, _b, _u, _v); 
} 

А потом, в D программе:

Color c = Color.create(42, 7, 19, 499, 727); 

printer.print(c); 

Так что c объект приходит из библиотеки C++, передается в объект printer, созданный в библиотеке C++, и эта передача выполняется в программе D.

И результаты неожиданно правильно:

$ ./main 
(42, 7, 19, 499, 727) 

Я пропускаю понятия C++ и D Interop или это ошибка в двух D составителей (недоверчиво)?

+2

AFAIK это дизайн. D способен взаимодействовать с C++, но он не может самостоятельно создавать объекты C++ (а объекты D имеют разный бинарный макет). Использование фабричного метода кажется правильным. –

ответ

3

Вы не должны использовать Ds new для выделения классов C++, если вы создаете Color :: getInstance, он работает.

import std.stdio; 

extern(C++) 
{ 
    class Color 
    { 
    this(uint _r, uint _g, uint _b, uint _u, uint _v) 
    { 
     r = _r; 
     g = _g; 
     b = _b; 
     u = _u; 
     v = _v; 
    } 

    uint r, g, b, u, v; 
    static Color getInstance(uint _r, uint _g, uint _b, uint _u, uint _v); 
    } 

    class Printer 
    { 
    @disable this(); 
    static Printer getInstance(); 
    final void print(Color c); 
    } 
} 

void main() 
{ 
    auto printer = Printer.getInstance(); 
    auto c = Color.getInstance(42, 7, 19, 499, 727); 

    printer.print(c); 
} 

и

#include <stdio.h> 

class Color 
{ 
public: 
    Color(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) : r(_r), g(_g), b(_b), u(_u), v(_v) {} 

    unsigned int r, g, b, u, v; 
    static Color* getInstance (unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v); 
}; 

Color* Color::getInstance(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) 
{ 
    return new Color(_r, _g, _b, _u, _v); 
} 

class Printer 
{ 
public: 
    Printer() {} 
    ~Printer() {} 
    static Printer* getInstance(); 
    void print(Color *c); 
}; 

Printer* Printer::getInstance() 
{ 
    return new Printer(); 
} 

void Printer::print(Color *c) 
{ 
    printf("(%d, %d, %d, %d, %d)\n", c->r, c->g, c->b, c->u, c->v); 
} 
+0

Но это звучит как обход проблемы, не так ли? .. Есть ссылка на D docs: http://dlang.org/spec/cpp_interface.html#memory-allocation, говорящий «Оставляя указатель на него на stack (как параметр или автоматическая переменная) '* (... является решением такого рода проблем ...) * – shybovycha

+0

То есть для объектов, выделенных GC, чтобы предотвратить их сбор, потому что GC не знает что C++ все еще имеет ссылки на эти объекты. Например, если вы храните GC-выделенный объект в массиве C++. – NotSpooky