Ошибка «не может получить доступ к закрытому члену» только тогда, когда класс имеет экспортную связь - PullRequest
16 голосов
/ 03 января 2012

Недавно мне пришлось изменить спецификацию связывания нескольких классов, и я столкнулся с проблемой.Два класса содержат std::map с std::unique_ptr в качестве типа значения.После того, как связь была изменена, компилятор начал жаловаться с «не может получить доступ к закрытому члену, объявленному в классе« 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>
      ]

Ответы [ 3 ]

23 голосов
/ 03 января 2012

Ошибка возникает из-за того, что компилятор не может создать конструктор копирования и оператор назначения копирования для ExportedClass.Это потребует копирования объектов unique_ptr, которые не имеют конструкторов копирования (они являются подвижными, но не копируемыми).

Для обычного класса ошибка не дается, потому что конструктор / назначение копирования фактически нигде не используется.Однако, когда присутствует __declspec (dllexport), создаются все функции, сгенерированные компилятором (не уверен насчет правильной терминологии здесь, но что-то вроде этого:).

Один из способов исправить ошибку - определить эти две функции для ExportedClassи пометить их как личные:

struct __declspec(dllexport) ExportedClass
{
    std::map<int, std::unique_ptr<SomeInterface>>   mData;
private:
    ExportedClass(const ExportedClass&) {}
    ExportedClass& operator=(const ExportedClass&) { return *this; }
};
2 голосов
/ 03 января 2012

Я столкнулся с этим очень давно, поэтому подробности немного размыты.

По сути, когда вы экспортируете класс, вы должны экспортировать все содержащиеся в нем классы - публичные или нет.В вашем случае это будет std::map и std::unique_ptr.Я не уверен, как классы в стандартных библиотеках ведут себя здесь, это расплывчатая часть, но я помню, что у меня были проблемы с этим.

Решение - либо экспортировать эти классы, либо использовать PIMPL реализация (которая в любом случае является хорошей идеей для экспортируемых классов).

1 голос
/ 07 февраля 2014

Часто 'std::move(iUniquePtr)' где-то отсутствует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...