[HOWTO] クラスの内部および外部にある STL コンポーネントをエクスポートする方法

概要

この資料は、以下の項目についてその具体的な方法を示したものです。
  • インスタンス化した Standard Template Library (STL) クラスをエクスポートする方法
  • STL オブジェクトであるデータ メンバが含まれるクラスをエクスポートする方法
インスタンス化される前のテンプレートはエクスポートできない点に注意してください。テンプレートはインスタンス化する必要があります。つまり、インスタンスを生成する際に、テンプレートのパラメータをすべて提供し、型を完全に定義しなければなりません。たとえば、"stack<int>;" と記述することで、STL の stack クラスがインスタンス化されます。このインスタンス化によって、クラス stack<int> のすべてのメンバが生成されます。


また、STL コンテナの中にはエクスポートできないもの (map、set、queue、list、deque) がある点にも注意してください。詳細については、「関連情報」を参照してください。

詳細

Visual C++ 5.0 以降、テンプレート クラスのインスタンス生成を強制し、インスタンス化したものをエクスポートすることが可能になりました。テンプレート クラスをインスタンス化したものをエクスポートするには、以下に示す構文を使用してください。

STL クラスをエクスポートするには

  1. DLL ファイルと .exe ファイルの両方で、同じバージョンの C ランタイム DLL をリンクします。両方のファイルを Msvcrt.lib (リリース ビルド) か、または Msvcrtd.lib (デバッグ ビルド) にリンクします。
  2. DLL では、テンプレートをインスタンス化する宣言に __declspec 指定子を与えて、STL クラスをインスタンス化したものを DLL からエクスポートします。
  3. .exe ファイルでは、テンプレートをインスタンス化する宣言に extern および __declspec の各指定子を与えて、DLL からクラスをインポートします。この結果として、warning C4231 "非標準の拡張機能が使用されています : 'extern' がテンプレートの明示的なインスタンス生成の前に見つかりました。" という警告メッセージが表示されます。この警告は無視してかまいません。

STL オブジェクトのデータ メンバが含まれるクラスをエクスポートするには

  1. DLL ファイルと .exe ファイルの両方で、同じバージョンの C ランタイム DLL をリンクします。両方のファイルを Msvcrt.lib (リリース ビルド) か、または Msvcrtd.lib (デバッグ ビルド) にリンクします。
  2. DLL では、テンプレートをインスタンス化する宣言に __declspec 指定子を与えて、STL クラスをインスタンス化したものを DLL からエクスポートします。


    : 手順 2. を省略することはできません。STL クラスをインスタンス化したものがデータ メンバの作成に使われている場合、それをエクスポートする必要があります。
  3. DLL では、クラスの宣言に __declspec 指定子を与えて、そのクラスを DLL からエクスポートします。
  4. .exe ファイルでは、クラスの宣言に __declspec 指定子を提供して、そのクラスを DLL からインポートします。


    エクスポートするクラスに 1 つ以上の基本クラスがある場合、基本クラスも同様にエクスポートする必要があります。エクスポートするクラスにクラス型のデータ メンバが含まれている場合、そのデータ メンバのクラスも同様にエクスポートする必要があります。
: STL クラスの中には、ほかの STL クラスを使用しているものがあります。これらのほかのクラスもエクスポートする必要があります。1 よりも低い警告レベル、つまり /W2、/W3、または /W4 を指定してコンパイルを実行すると、エクスポートしなければならないクラスの一覧がコンパイラの警告に表示されます。警告レベル 4 では、STL ヘッダーに関する警告が大量に生成されるため、現状ではお勧めできません。


STL クラスの中には、ネストしたクラスを含むものがあります。これらのクラスをエクスポートすることはできません。たとえば、deque にはネストしたクラス deque::iterator が含まれています。deque をエクスポートすると、deque::iterator をエクスポートしなければならないという警告が表示されます。deque::iterator をエクスポートすると、deque をエクスポートしなければならないという警告が表示されます。これは、いったんテンプレート クラスをインスタンス化すると、それを再度インスタンス化してエクスポートすることはできないという、設計上の制約により発生します。現在エクスポートできる唯一の STL コンテナは vector です。そのほかのコンテナ (つまり、map、set、queue、list、deque) にはすべて、ネストしたクラスが含まれており、エクスポートすることはできません。


ユーザー定義型 (UDT) をパラメータに指定した STL コンテナをエクスポートする場合は、指定した UDT に対応する < と == の各演算子を定義する必要があります。たとえば、vector<MyClass> をエクスポートする場合は、MyClass::operator < と MyClass::operator == を定義する必要があります。この理由は、すべての STL コンテナ クラスにはメンバ比較演算子が用意されており、コンテナに含める型に対応する < と == の演算子の存在が必要になるためです。通常、これらは使用されないため、インスタンス化されません。テンプレート クラスのインスタンスを生成すると、すべてのメンバ関数が生成されます。STL コンテナ クラスには、コンテナに含める型に対応した < と == の各演算子を使用するメンバ関数があるため、これらを実装する必要があります。指定した UDT のオブジェクトの比較が意味をなさない場合、単純に "true" を返す比較演算子を定義することもできます。


コンパイルの際にシンボル _DLL (このシンボルは、/MD か /MDd でコンパイルして DLL バージョンの C ランタイムにリンクすると暗黙で定義されます) を定義すると、以下の STL クラス、およびこれらのクラスに作用する各種のグローバル演算子や関数が、既に C 言語のランタイム DLL でエクスポートされています。このため、ユーザーの DLL からこれらをエクスポートすることはできません。ユーザーのクラスをインポートする実行プログラムが、DLL バージョンの C ランタイムも使用している限り、これが問題になることはありません。

ヘッダー STL テンプレート クラス
------------------------------
<IOSFWD> basic_ios
<IOSFWD> <IOSFWD>
<IOSFWD> basic_istream
<IOSFWD> basic_string (string および wstring としても typedef されています)
<IOSFWD> complex
<LOCALE> messages
<XLOCALE> codecvt
<XLOCALE> ctype
<XLOCMON> moneypunct
<XLOCMON> money_get
<XLOCMON> money_put
<XLOCNUM> numpunct
<XLOCTIME> time_get
<XLOCTIME> time_put
<XSTRING> basic_string (string および wstring としても typedef されています)
使用するテンプレート パラメータや、宣言するグローバル関数や演算子の具体的な詳細については、関連するヘッダー ファイルを参照してください。

サンプル コード

   // -------------------------------------------
// MYHEADER.H
// 255 文字より長いシンボルを持つコードのデバッグに関する警告を抑制
#pragma warning (disable : 4786)
// テンプレートをインスタンス化する前の extern に関する警告を抑制
#pragma warning (disable : 4231)

#include <vector>

// 記憶クラス指定子 (.exe ファイルに対しては extern、DLL に対しては指定なし)、
// および __declspec 指定子 (.exe ファイルに対しては dllimport、DLL に対しては
// dllexport) を提供します。
// DLL をコンパイルする際には、EXP_STL を定義する必要があります。
// これで、このヘッダーファイルを .exe ファイルと DLL の両方で使用できます。
// 共通の宣言を使用する方が、別の 2 つのヘッダー ファイルを使用するよりも
// はるかに安全です。
#ifdef EXP_STL
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif

// クラス vector<int> および vector<char> をインスタンス化
// ここではオブジェクトは生成されません。 クラス vector<int> および
// vector<char> のメンバすべての生成が強制されるだけです。これらは
// DLL からエクスポートされた後、.exe ファイルにインポートされます。
EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<int>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<char>;

// STL オブジェクトの静的データ メンバと非静的データ メンバの
// 両方が含まれるクラスを宣言および定義します。
// データ メンバをアクセス可能にするには、上記 2 つのテンプレートを
// インスタンス化したものが必要なことに注意してください。上記のインスタンス生成を
// 省略すると、アクセス違反のエラーが発生します。
// MyClass の vector をエクスポートしているため、演算子 < と
// 演算子 == の実装を提供する必要がある点に注意してください。
class DECLSPECIFIER MyClass
{
public:
std::vector<int> VectorOfInts;
static std::vector<char> StaticVectorOfChars;

public:
bool operator < (const MyClass c) const
{
return VectorOfInts < c. VectorOfInts;
}
bool operator == (const MyClass c) const
{
return VectorOfInts == c. VectorOfInts;
}
};

// クラス vector<MyClass> をインスタンス化
// ここではオブジェクトは生成されません。クラス vector<MyClass> の
// メンバすべての生成が強制されるだけです。これらは DLL から
// エクスポートされた後、.exe ファイルにインポートされます。
EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<MyClass>;

// -------------------------------------------
// 必要なコンパイル オプション : /GX /LDd /MDd /D"EXP_STL"
// または : /GX /LD /MD /D"EXP_STL"
// DLL.CPP

#include "MyHeader.h"
std::vector<char> MyClass::StaticVectorOfChars;

// -------------------------------------------
// 必要なコンパイル オプション : /GX /MDd
// または : /GX /MD
// EXE.CPP

#include <iostream>
#include "MyHeader.h"

int main ()
{
MyClass x;

for (int i=0; i<5; i++) x.VectorOfInts.push_back(i);
for (char j=0; j<5; j++) x.StaticVectorOfChars.push_back('a' + j);

std::vector<int>::iterator vii = x.VectorOfInts.begin();
while (vii != x.VectorOfInts.end())
{
std::cout << *vii;
std::cout << " displayed from x.VectorOfInts" << std::endl;
vii++;
}
std::vector<char>::iterator vci = x.StaticVectorOfChars.begin();
while (vci != x.StaticVectorOfChars.end())
{
std::cout << *vci;
std::cout << " displayed from MyClass::StaticVectorOfChars";
std::cout << std::endl;
vci++;
}

std::vector<MyClass> vy;
for (i=0; i=5; i++) vy.push_back(MyClass());

return 1;
}

関連情報

関連情報については、Visual C++ のヘルプで次のトピックを検索してください。
明示的なインスタンス作成

__declspec

stack

/MD、/ML、/MT、/LD (ランタイム ライブラリの使用)

関連情報

この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID
168958 (最終更新日 2001-05-05) をもとに作成したものです。


プロパティ

文書番号:168958 - 最終更新日: 2004/01/30 - リビジョン: 1

フィードバック