2012-01-03 32 views
15

Gần đây tôi đã phải thay đổi đặc tả liên kết của một số lớp và gặp sự cố. Hai trong số các lớp có chứa std::map với một loại giá trị std::unique_ptr. Sau khi liên kết đã được thay đổi trình biên dịch bắt đầu phàn nàn với "không thể truy cập thành viên tư nhân khai báo trong lớp 'std :: unique_ptr < _Ty>'" lỗi."không thể truy cập thành viên riêng" "chỉ khi lớp có liên kết xuất

Bất cứ ai cũng biết tại sao điều này chỉ xảy ra khi đặc tả xuất khẩu được cung cấp hoặc có giải pháp?

Mã mẫu:

#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; 
}; 

biên dịch ra:

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

Ít nhất, đây là vấn đề cụ thể về nền tảng và trình biên dịch. C++ không có ABI chuẩn hóa và các hiệu ứng của '__declspec (declexport)' trên định nghĩa * class * hoàn toàn phụ thuộc vào trình biên dịch. –

Trả lời

22

Lỗi được đưa ra vì trình biên dịch không thể tạo hàm tạo bản sao và sao chép toán tử gán cho ExportedClass. Điều đó đòi hỏi phải sao chép các đối tượng unique_ptr không có các hàm tạo bản sao (chúng có thể di chuyển nhưng không thể sao chép được).

Đối với lớp bình thường, lỗi này không được đưa ra bởi vì hàm tạo/gán bản sao không thực sự được sử dụng ở bất kỳ đâu. Tuy nhiên khi __declspec (dllexport) xuất hiện tất cả các hàm được tạo ra của trình biên dịch được khởi tạo (không chắc chắn về thuật ngữ đúng ở đây nhưng một cái gì đó tương tự :).

Một cách để sửa chữa các lỗi là để xác định những hai chức năng cho ExportedClass và đánh dấu chúng là cá nhân:

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

Đó là vé. Neet-O! –

+1

Khi bạn xuất một loại, thì toàn bộ giao diện công cộng cộng với mọi thứ được sử dụng bởi các hàm nội tuyến cũng cần phải được xuất. Xem tài liệu về [cảnh báo C4251] (http://msdn.microsoft.com/en-us/library/esew7y1w.aspx) để biết chi tiết. –

+0

Tôi đã nhận thức được C4251 tuy nhiên việc giải quyết nó trong mã ví dụ sẽ là sự lộn xộn vô nghĩa và không liên quan đến câu hỏi của tôi. –

2

Tôi chạy vào trong này một thời gian dài trước đây, vì vậy các chi tiết này là hơi mờ.

Thực chất khi bạn xuất một lớp, bạn phải xuất tất cả các lớp có sẵn - công khai hay không. Trong trường hợp của bạn sẽ là std::mapstd::unique_ptr. Tôi không chắc các lớp trong thư viện chuẩn hoạt động như thế nào ở đây, đó là phần mờ, nhưng tôi nhớ đã có vấn đề với điều đó.

Giải pháp là xuất các lớp đó hoặc sử dụng triển khai PIMPL (đây là ý tưởng hay cho các lớp được xuất).

+0

Sử dụng giao diện lớp DLL của PIMPL làm cho mọi thứ dễ dàng hơn nhiều :) – paulm

0

Thường thì một 'std::move(iUniquePtr)' là mất tích ở đâu đó.

Các vấn đề liên quan