Как передать объект из D в C++?

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

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

У меня есть библиотека 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: что еще более интересно и (вероятно) указывает на то, в чем заключается проблема, это объекты факта, созданные в C++ lib, которые правильно передаются между 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 или это ошибка в двух компиляторах D (сомнительно)?

1 ответ

Решение

Вы не должны использовать 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);
}
Другие вопросы по тегам