2012-01-03 11 views
15

最近、いくつかのクラスのリンケージ仕様を変更しなければならず、問題が発生しました。 2つのクラスには、値タイプとしてstd::unique_ptrstd::mapが含まれています。リンケージが変更された後、コンパイラは "クラス 'std :: unique_ptr < _Ty>'エラーで宣言されたプライベートメンバーにアクセスできません。"クラスにエクスポートリンクがある場合にのみプライベートメンバーにアクセスできません" "

輸出仕様が提供されている場合や解決策がある場合にのみ、これがなぜ発生するのでしょうか。

サンプルコード:

#include <map> 

struct SomeInterface 
{ 
    virtual ~SomeInterface() = 0; 
}; 


// This class compiles with no problems 
struct LocalClass 
{ 
    std::map<int, std::unique_ptr<SomeInterface>> mData; 
}; 

// This class fails to compile 
struct __declspec(dllexport) ExportedClass 
{ 
    std::map<int, std::unique_ptr<SomeInterface>> mData; 
}; 

コンパイラ出力:

c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(163): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
     with 
     [ 
      _Ty=SomeInterface 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(2347) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr' 
     with 
     [ 
      _Ty=SomeInterface 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(195) : see reference to function template instantiation 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base<const int&,_Ty2&>(_Other1,_Other2)' being compiled 
     with 
     [ 
      _Ty1=const int, 
      _Ty2=std::unique_ptr<SomeInterface>, 
      _Other1=const int &, 
      _Other2=std::unique_ptr<SomeInterface> & 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\xmemory(208) : see reference to function template instantiation 'std::pair<_Ty1,_Ty2>::pair<const _Kty,_Ty>(std::pair<_Ty1,_Ty2> &)' being compiled 
     with 
     [ 
      _Ty1=const int, 
      _Ty2=std::unique_ptr<SomeInterface>, 
      _Kty=int, 
      _Ty=std::unique_ptr<SomeInterface> 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\xmemory(280) : see reference to function template instantiation 'void std::allocator<_Ty>::construct<std::pair<_Ty1,_Ty2>&>(std::pair<_Ty1,_Ty2> *,_Other)' being compiled 
     with 
     [ 
      _Ty=std::pair<const int,std::unique_ptr<SomeInterface>>, 
      _Ty1=const int, 
      _Ty2=std::unique_ptr<SomeInterface>, 
      _Other=std::pair<const int,std::unique_ptr<SomeInterface>> & 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree(592) : see reference to function template instantiation 'void std::_Cons_val<std::allocator<_Ty>,_Ty,std::pair<_Ty1,_Ty2>&>(_Alloc &,std::pair<_Ty1,_Ty2> *,std::pair<_Ty1,_Ty2>)' being compiled 
     with 
     [ 
      _Ty=std::pair<const int,std::unique_ptr<SomeInterface>>, 
      _Ty1=const int, 
      _Ty2=std::unique_ptr<SomeInterface>, 
      _Alloc=std::allocator<std::pair<const int,std::unique_ptr<SomeInterface>>> 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree(1521) : see reference to function template instantiation 'std::_Tree_nod<_Traits>::_Node *std::_Tree_val<_Traits>::_Buynode<std::pair<_Ty1,_Ty2>&>(_Valty)' being compiled 
     with 
     [ 
      _Traits=std::_Tmap_traits<int,std::unique_ptr<SomeInterface>,std::less<int>,std::allocator<std::pair<const int,std::unique_ptr<SomeInterface>>>,false>, 
      _Ty1=const int, 
      _Ty2=std::unique_ptr<SomeInterface>, 
      _Valty=std::pair<const int,std::unique_ptr<SomeInterface>> & 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree(1516) : while compiling class template member function 'std::_Tree_nod<_Traits>::_Node *std::_Tree<_Traits>::_Copy(std::_Tree_nod<_Traits>::_Node *,std::_Tree_nod<_Traits>::_Node *)' 
     with 
     [ 
      _Traits=std::_Tmap_traits<int,std::unique_ptr<SomeInterface>,std::less<int>,std::allocator<std::pair<const int,std::unique_ptr<SomeInterface>>>,false> 
     ] 
     c:\program files (x86)\microsoft visual studio 10.0\vc\include\map(81) : see reference to class template instantiation 'std::_Tree<_Traits>' being compiled 
     with 
     [ 
      _Traits=std::_Tmap_traits<int,std::unique_ptr<SomeInterface>,std::less<int>,std::allocator<std::pair<const int,std::unique_ptr<SomeInterface>>>,false> 
     ] 
     c:\projects\so\so\so.cpp(18) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled 
     with 
     [ 
      _Kty=int, 
      _Ty=std::unique_ptr<SomeInterface> 
     ] 
+2

少なくとも、これはプラットフォームとコンパイラに固有の問題です。 C++は標準化されたABIを持っておらず、*クラス*定義に対する '__declspec(declexport)'の影響は完全にコンパイラによって異なります。 –

答えて

22

コンパイラがExportedClassのコピーコンストラクタおよびコピー代入演算子を作成できないため、エラーが発生します。コピーコンストラクタを持たないunique_ptrオブジェクトをコピーする必要があります(これらは移動可能ですがコピーできません)。

通常のクラスでは、コピーコンストラクタ/割り当てがどこにも実際には使用されないため、エラーは発生しません。しかし、__declspec(dllexport)が存在する場合、コンパイラ生成関数はすべてインスタンス化されます(ここで正しい用語についてはわかりませんが:)。

struct __declspec(dllexport) ExportedClass 
{ 
    std::map<int, std::unique_ptr<SomeInterface>> mData; 
private: 
    ExportedClass(const ExportedClass&) {} 
    ExportedClass& operator=(const ExportedClass&) { return *this; } 
}; 
+1

これはチケットです。 Neet-O! –

+1

タイプをエクスポートするときは、インライン関数で使用されるすべてのパブリック・インタフェースに、エクスポートする必要があります。 詳細については、[警告C4251](http://msdn.microsoft.com/en-us/library/esew7y1w.aspx)のドキュメントを参照してください。 –

+0

私は既にC4251を認識していますが、サンプルコードでそれを扱うことは無意味なものになってしまい、私の質問には無頓着です。 –

2

私は長い時間前にこれに走ったので、これまで詳細が少しぼやけています。

本質的に、クラスをエクスポートするときには、含まれているクラスもすべて公開するかどうかをエクスポートする必要があります。あなたの場合は、std::mapstd::unique_ptrとなります。標準ライブラリのクラスがここでどのように振る舞うかはわかりませんが、それはぼんやりした部分ですが、問題があったことを覚えています。

解決策は、これらのクラスをエクスポートするか、PIMPLの実装を使用することです(これは、エクスポートされたクラスの場合はお勧めです)。

+0

DLLクラスインターフェイスにPIMPLを使用すると、作業がはるかに簡単になります:) – paulm

0

をしばしば「std::move(iUniquePtr)」はどこか欠落しています。エラーを修正する

一つの方法は、ExportedClassのために、これら二つの関数を定義し、プライベートとしてマークすることです。

関連する問題