このページを読むことをお勧めします。Dで呼び出すことができるC++クラスの関数は、仮想関数のみです。つまり、
DはC++の特殊メンバー関数を呼び出すことはできません。その逆も同様です。これらには、コンストラクタ、デストラクタ、変換演算子、演算子のオーバーロード、およびアロケータが含まれます。
また、DでC ++クラスを宣言するときは、を使用しextern(C++) interface
ます。したがって、クラス/構造体は次のようになります
extern(C++) interface A
{
void fun();
}
ただし、Dコードはコンストラクターにアクセスできないため、C ++コードがそれを実行する必要があるためextern(C++)
、タイプのオブジェクトを割り当てるには別の関数が必要になります。A
また、C ++コードに戻して、使い終わったら削除する方法も必要です。
extern(C++)
ここで、そのインターフェイスを、関数を呼び出して構築し、関数を削除する型でラップextern(C++)
する場合(手動で行うことを心配する必要がないように)、クラスを使用するかどうかまたは構造体は、それを使って何をしようとしているかに完全に依存します。
クラスは参照型であり、C++クラスが実際に何であるかを反映しています。したがって、特別なことをしなくても、それを渡すことができます。ただし、ラップされたC ++オブジェクトが解放されることを保証したい場合は、手動で行う必要があります。これは、Dクラスのファイナライザーが実行される保証がないためです(おそらく、ここにコードを配置します)。 C++関数を呼び出してC++オブジェクトを削除します)。clear
Dオブジェクトを破棄するには(実際にはコンパイラの次のリリースで名前が変更される-dmd destroy
2.060)を使用する必要があります(つまり、ファイナライザを呼び出して、値型であるメンバー変数の破棄を処理します) 、またはC ++オブジェクトを削除するには、C++関数を呼び出したDオブジェクトの関数を呼び出す必要があります。例えば
extern(C++) interface A
{
void fun();
}
extern(C++) A createA();
extern(C++) void deleteA(A a);
class Wrapper
{
public:
this()
{
_a = createA();
}
~this()
{
deleteA(_a);
}
auto opDispatch(string name, Args...)(Args args)
{
return mixin("_a." ~ name ~ "(args)");
}
private:
A _a;
}
void main()
{
auto wrapped = new Wrapper();
//do stuff...
//current
clear(wrapped);
//starting with dmd 2.060
//destroy(wrapped);
}
clear
ただし、これには、 /destroy
を呼び出さず、ガベージコレクターがラッパーオブジェクトを収集しdeleteA
ない場合、C++オブジェクトで呼び出されないという欠点があります。それは問題かもしれないし、問題ではないかもしれません。これは、プログラムが終了する前にC ++オブジェクトが本当にデストラクタを呼び出す必要があるかどうか、またはプログラムが終了したときにGCがラッパーを収集する必要がない場合にメモリをOSに戻すことができるかどうかによって異なります。物体。
決定論的破壊が必要な場合は、構造体が必要です。つまり、構造体を参照型にすることについて心配する必要があります。それ以外の場合、コピーされた場合、一方が破棄されるとC ++オブジェクトが削除され、もう一方の構造体はガベージをポイントします(破棄されると削除を試みます)。これを解決するには、を使用できますstd.typecons.RefCounted
。次に、あなたは次のようなものを手に入れます
extern(C++) interface A
{
void fun();
}
extern(C++) A createA();
extern(C++) void deleteA(A a);
struct Wrapper
{
public:
static Wrapper opCall()
{
Wrapper retval;
retval._a = createA();
return retval;
}
~this()
{
if(_a !is null)
{
deleteA(_a);
_a = null;
}
}
auto opDispatch(string name, Args...)(Args args)
{
return mixin("_a." ~ name ~ "(args)");
}
private:
A _a;
}
void main()
{
auto wrapped = RefCounted!Wrapper();
//do stuff...
}
参照カウントロジックが含まれるようにラッパーを定義して回避することもできますが、RefCounted
それは間違いなくより複雑になります。
bool
とにかく、ラッパーがC ++オブジェクトを所有しているかどうかをマークするためにを使用するという提案には絶対に反対します。これは、すべてのコピーが破棄される前に元のラッパーオブジェクトが破棄されると、コピーがガベージを指すためです。
C ++オブジェクトのコピーコンストラクターを使用したい場合(したがって、C ++オブジェクトを値型として扱う場合)の別のオプションは、C ++オブジェクトextern(C++)
を取得してそのコピーを返し、ポストブリットで使用する関数を追加することです。 。
extern(C++) A copyA(A a);
this(this)
{
if(_a !is null)
_a = copyA(a);
}
うまくいけば、それは物事を十分に明確にするでしょう。