2016-03-23 50 views
5

Próbuję nawiązać współpracę z C++ i D. A to, co znalazłem dzisiaj, naprawdę psuje mój umysł: obiekty nie są poprawnie przekazywane w moim programie.Jak przekazać obiekt z D do C++?

Lepiej pokazać przykład.

Mam bibliotekę C++, którą kompiluję do pliku obiektowego i programu D, który łączę z moją biblioteką i uruchamiam.

Oto one:

#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); 
} 

a program 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); 
} 

skompilować je z tych poleceń:

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

Ale kiedy biegnę ./main, mam dziwne wyniki:

(113244372, 1, 42) 

Co sprawiło, że myślę, że obiekty są przekazywane nieprawidłowo to po prostu prosty eksperyment. Po pierwsze, wpadłem mój program kilka razy i oto co zobaczyłam:

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

Więc pierwsza liczba wydaje się być wskaźnik do bloku pamięci. Szóste uczucie w połączeniu ze znajomością montażu powoduje, że myślę, że jest to wskaźnik do zmiennej this.

A teraz, żeby potwierdzić moje dane nadal jest na swoim miejscu i te numery nie są jedynie przypadkowe te, dodałem dwa kolejne pola do mojego klasy 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); 
} 

a program 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); 
} 

a wyjścia są:

$ ./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) 

Próbowałem już skompilować mój program z kompilatorami DMD i LDC, ale oba zapewniły mi dokładnie to samo zachowanie.

UPD: Co jeszcze bardziej interesujące i (prawdopodobnie) wskazując, gdzie leży problem, to fakt, że obiekty stworzone w C++ lib są przekazywane pomiędzy D i C++ poprawnie.

Aby to udowodnić, stworzyłem "metody fabryki" w moim Color klasy:

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); 
} 

a następnie w programie D:

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

printer.print(c); 

tak aby obiekt c pochodzi z C++ biblioteki zostaje przekazany do obiektu printer, utworzonego w bibliotece C++ i ten transfer jest wykonywany w programie D.

a wyniki są niespodziewanie poprawne:

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

jestem brakuje koncepcji C++ i D współdziałanie czy jest to błąd w dwóch kompilatorów D (niepewnie)?

+2

AFAIK to jest zgodne z projektem. D jest zdolny do połączenia z C++, ale nie może samodzielnie tworzyć obiektów C++ (a obiekty D mają inny układ binarny). Używanie metody fabrycznej wydaje się poprawne. –

Odpowiedz

3

Nie powinieneś używać Ds new do alokowania klas C++, jeśli utworzysz Color :: getInstance, który działa.

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); 
} 

i

#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

Ale to brzmi jak pomijanie problemu, czyż nie? .. Istnieje wzmianka na temat D docs: http://dlang.org/spec/cpp_interface.html#memory-allocation mówiąc: Pozostawienie na niej wskaźnika stos (jako parametr lub zmienna automatyczna) '* (... jest rozwiązaniem tego rodzaju problemów ...) * – shybovycha

+0

To jest dla obiektów przydzielonych z GC, aby zapobiec ich zbieraniu, ponieważ GC nie wie że C++ nadal ma odniesienia do tych obiektów. Na przykład, jeśli przechowujesz obiekt przydzielony przez GC w tablicy C++. – NotSpooky