使用 D 中的 C++ 构造函数
Using C++ constructors from D
D wiki 上有一个关于 C++ 接口的页面 - https://dlang.org/spec/cpp_interface.html
它说您可以 link C++ 代码但不能 link 特殊方法,包括构造函数、析构函数和运算符重载,因为对象的生命周期问题。建议使用包装器(并在 C/C++ 端构造对象)或使用 D 重新实现构造函数。这两种方法都需要完成大量工作,有时甚至是不可能的。如果你想在你的 D 程序中使用一些 C++ 库,这感觉是一个大问题:例如,你想使用 Qt 的 QML 并且可以定义需要的 类 与 extern(C++)...
一起使用,但是你坚持使用构造函数和大量包装器(如 dqml
项目)或移植代码。
但有一种方法看起来很有效。简单示例:
//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;
};
我将这段代码编译成class.lib
到link,稍后在这个D程序中使用:
//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();
}
通过这种方式,我手动将 D 构造函数名称更改为 C++ 名称,因为我无法让编译器自己执行此操作。然后我只是在循环中创建和检查对象,并通过任务管理器观察进程内存使用情况。每次检查都很好(因此 z
初始化程序和正确调用构造函数的设置 x
)并且我没有看到内存泄漏(所以看起来 D 在十亿次迭代中没有任何问题地创建和销毁对象).
问题是:这样调用构造函数(和析构函数)有没有隐藏的问题?在更困难的条件下是否存在任何内存问题或类似导致程序崩溃的问题?或者在某些情况下可能会出现一些奇怪的行为?
问题是 C++ 和 D 的构造函数和析构函数以不同的顺序和不同的时间做类似的事情。
- 在调用 D 构造函数之前初始化内存。 C++构造函数自行清空内存
- 当对象超出范围时调用 C++ 析构函数。在 D 中,垃圾收集器调用析构函数。
当您开始在 C++ 和 D 之间混合 class 层次结构时,这很容易导致麻烦。
但在您的示例的简单情况下(仅调用 ctor,没有继承组合)应该没有问题。
D wiki 上有一个关于 C++ 接口的页面 - https://dlang.org/spec/cpp_interface.html
它说您可以 link C++ 代码但不能 link 特殊方法,包括构造函数、析构函数和运算符重载,因为对象的生命周期问题。建议使用包装器(并在 C/C++ 端构造对象)或使用 D 重新实现构造函数。这两种方法都需要完成大量工作,有时甚至是不可能的。如果你想在你的 D 程序中使用一些 C++ 库,这感觉是一个大问题:例如,你想使用 Qt 的 QML 并且可以定义需要的 类 与 extern(C++)...
一起使用,但是你坚持使用构造函数和大量包装器(如 dqml
项目)或移植代码。
但有一种方法看起来很有效。简单示例:
//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;
};
我将这段代码编译成class.lib
到link,稍后在这个D程序中使用:
//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();
}
通过这种方式,我手动将 D 构造函数名称更改为 C++ 名称,因为我无法让编译器自己执行此操作。然后我只是在循环中创建和检查对象,并通过任务管理器观察进程内存使用情况。每次检查都很好(因此 z
初始化程序和正确调用构造函数的设置 x
)并且我没有看到内存泄漏(所以看起来 D 在十亿次迭代中没有任何问题地创建和销毁对象).
问题是:这样调用构造函数(和析构函数)有没有隐藏的问题?在更困难的条件下是否存在任何内存问题或类似导致程序崩溃的问题?或者在某些情况下可能会出现一些奇怪的行为?
问题是 C++ 和 D 的构造函数和析构函数以不同的顺序和不同的时间做类似的事情。
- 在调用 D 构造函数之前初始化内存。 C++构造函数自行清空内存
- 当对象超出范围时调用 C++ 析构函数。在 D 中,垃圾收集器调用析构函数。
当您开始在 C++ 和 D 之间混合 class 层次结构时,这很容易导致麻烦。
但在您的示例的简单情况下(仅调用 ctor,没有继承组合)应该没有问题。