2017-02-10 7 views
1

私は0122,を介して、C++のdll境界について読んでいます。C++のDllの境界は、抽象的なインターフェイスを使用して - ヘッダーの>スマートポインタ?削除を呼び出す?

私は単一のプロジェクトで実装例を書いた。

main.cpp

#include <iostream> 
#include <memory> 
#include <functional> 
#include "Interface.hpp" 

typedef std::shared_ptr<Interface> IPTR; 

int main() 
{ 
    IPTR ptr = std::shared_ptr<Interface>(MakeInterface(), std::mem_fn(&Interface::Release)); 
    std::cout << ptr->Foo(4) << "\n"; 
} 

Interface.hpp

#define MyAPI /*export/import*/ 
#define APIENTRY __stdcall 

struct MyAPI Interface 
{ 
    virtual int Foo(int n) = 0; 
    virtual void Release() = 0; 
}; 

extern "C" MyAPI Interface* APIENTRY MakeInterface(); 

Interface.cpp

#include "Interface.hpp" 

struct InterfaceImpl : Interface 
{ 
    virtual int Foo(int n){ return n; } 
    virtual void Release(){ delete this; } 
}; 

extern "C" MyAPI Interface* APIENTRY MakeInterface() 
{ 
    return new InterfaceImpl{}; 
} 

私の質問は

    です
  • スマートポインタ宣言をC++のdllの問題に陥らずにヘッダーに移動できますか?
  • Releaseメソッドでdelete thisに電話するのは正しいですか?
+0

技術的には、「dllの境界はC++で」(まだ)存在しません。なぜCOMを書き直したいのですか? –

+0

@ダン私はあなたの意見を見て、瞬時に私が何を得ているかを知っていました:) – Johannes

+0

しかし、あまりにも多くの貧弱なC++の質問を読んだ後は、よく尋ねられたものを見てうれしいです... :-) * Sei gegruesst!* –

答えて

1

1)番

extern "C" MyAPI Interface* APIENTRY MakeInterface() 
{ 
    return new InterfaceImpl{}; 
} 

このnewを持っており、実行可能ファイルからnewと互換性がないことができます。 delete(実行可能ファイル)によってオブジェクトを破棄すると、メモリマネージャが異なるために機能しないことがあります。経験則:作成/作成機能(ファクトリ)を提供する場合は、破棄/空き/削除機能を提供する必要があります。 Releaseメソッドは動作しますが、MakeInterfaceとは異なる抽象レベルにあります。 2つの親指のルール:pimplと組み合わせて独立した標準のレイアウトタイプをエクスポートします。

2.)はい。

+0

私の印象は、MakeInterfaceとReleaseメソッドの両方がDLLにあり、同じメモリマネージャを使用していることです。一般に、1つのモジュールで割り振り、別のモジュールで割り当てを解除する機会を十分に認識しておく必要があります。 (これは一般に、ある操作または他の操作がヘッダーファイルであるため、どちらのモジュールにもインライン展開できます)。これは、ランタイムライブラリに静的にリンクするのではなく、DLLランタイムに依存する理由の1つです。 –

+0

はい、同じDLLにあります。異なる抽象化レベル:自由関数対メンバ関数。私は作成と削除のための自由な機能を好むだろう。クラスには "プライベート"なコンストラクタと破壊が必要です。あなたの第2のポイント:静的なランタイムリンク(可能な場合)のために、ほとんどのDLLインターフェイスを設計します。これは単にコンパイラフラグを設定する以上のことを意味します。 – knivil

1

使用する方法は、私たちが仕事場で使用しているものを使用しています。 あなたが注意しなければならないことの1つは、インターフェイスの引数として、最大でp個のCデータ型だけを渡すことです。 メモリの問題が発生する可能性があります。たとえば あなたは文字列引数を使用してインタフェースの関数を定義する場合:あなたは、クライアントをコンパイルして、DLLの新しいバージョンを(異なるSTLバージョンでdllを考える場合は、問題が発生する場合があります

struct Mapi Interface 
{ 
    void wrong(string& a_string)=0 
}; 

、再コンパイルVITHのvs2015クライアントは古いままで、vs6でコンパイルされています)。

この例では、refを文字列に渡します。文字列の初期バッファは、クライアントによって割り当てられます。

dllで、a_stringに新しい値を割り当てます。これは、再割り当てが必要な大きさの値です。 このようにして、dllコンテキスト内の初期バッファを解放します。ヒープマネージャは、(異なるCRT)異なっていた場合は、DLL-ランタイムから使用されているメモリの問題に

+0

DLL内でランタイムに静的リンクを使用できます。 – knivil

+0

静的リンクの問題ではありません。同じC++ランタイムを共有しない限り、誰がメモリを割り当てるかは、そのメモリを解放する必要があります。 – alangab

関連する問題