Search code examples
c++d

Using C++ constructors from D


There is a page about C++ interfacing at D wiki - https://dlang.org/spec/cpp_interface.html

It says you can link to C++ code but cant link to special methods including constructors, destructors and operators overloads because of object's lifetime issues. It's suggested to either use a wrapper (and construct objects on C/C++ side) or reimplement constructor with D. Both ways require a lot of work to be done and sometimes can be impossible. This feels as a huge problem if you want to use some C++ library in your D program: for example, you want to use Qt's QML and can define needed classes to use with extern(C++)... but then you stuck with a constructors and lots of wrappers (like dqml project do) or ported code.

But there is a way that looks working. Simple example:

//class.h

class MyTestClass {
    int x = 0;
    int z = 0;

public:
    MyTestClass(int y);
    int getX();
    int getZ();
};

//class.cpp

#include "class.h"

MyTestClass::MyTestClass(int y) {
    x = y;
};

int MyTestClass::getX() {
    return x;
};

int MyTestClass::getZ() {
    return z;
};

I compile this code into class.lib to link and use later in this D program:

//main.d
import std.stdio;

extern(C++) {
    class MyTestClass {
        pragma(mangle, "??0MyTestClass@@QEAA@H@Z") this(int y);
        final int getX();
        final int getZ();
    }
}

void main()
{
    int checks = 0;
    int goal = 1_000_000_000;
    foreach (int i; 0 .. goal) {
        MyTestClass test = new MyTestClass(5);
        if (test.getX() == 5 && test.getZ() == 0) checks++;
    }
    writeln(checks, " successfull from ", goal);
    readln();
}

This way I manually mangle D constructor name to C++ one because there is no way I know about to let compiler do this itself. Then I just create and check objects in a loop and watch process memory usage via task manager. Every check goes fine (so both z initializer and setting x from constructor called properly) and I see no memory leak (so it looks like D is creating and destroying objects without any problems on a billion of iterations).

The question is: are there any hidden problems calling constructors (and destructors) this way? Any memory issues under more difficult conditions or something similar resulting in program crashes? Or some weird behaviour in certain cases maybe?


Solution

  • The problem is that C++ and D constructors and destructors do similar things in a different order and at different times.

    • Memory is initialized before a D constructor is called. The C++ constructor clears the memory by itself.
    • The C++ destructor is called when the object goes out of scope. In D the garbage collector calls the destructor.

    This can easily result in trouble when you start mixing the class hierarchy between C++ and D.

    But in the simple case of your example (only ctor called, no inheritance mix) there should be no problem.