2016-05-27 2 views
1

У меня проблема с созданием моего объекта, не подлежащего копированию. Пусть рассмотрим следующий пример:Uncopyable object, map и shared_ptr: ошибка в конструкторе копирования

class Uncopyable{ 
protected: 
    Uncopyable(){}; 
    ~Uncopyable(){}; 

private: 
    Uncopyable(const Uncopyable&); 
    Uncopyable& operator=(const Uncopyable&); 
}; 


class Base { }; 
class Derived : public Base { }; 

class A : private Uncopyable { 
public: 
    A(std::map<std::string, std::shared_ptr<Base>> & inMap); 
private: 
    A(const A&); 
    A& operator=(const A&); 
}; 

int main() { 
    std::map<std::string, std::shared_ptr<Derived>> lMap; 
    std::shared_ptr<A> oA(std::make_shared<A>(lMap)); 
} 

Если я предполагаю, что мой объект А быть не копируемыми, не work.As указатель, я ожидаю, мой объект А, чтобы понять, что производный является базовой, но вместо этого я я получаю следующее сообщение:

error C2664: 'A::A(const A &)' : cannot convert argument 1 from 'std::map<std::string,std::shared_ptr<Derived>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'std::map<std::string,std::shared_ptr<Base>,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>> &' 
1>   with 
1>   [ 
1>    _Kty=std::string 
1> ,   _Ty=std::shared_ptr<Derived> 
1>   ] 
1>   and 
1>   [ 
1>    _Kty=std::string 
1> ,   _Ty=std::shared_ptr<Base> 
1>   ] 

Спасибо.

ответ

3

Ошибка не связана с невозможностью копирования A и, действительно, не находится в конструкторе копирования - это в конструкторе map. Ошибка связана с тем, что A' конструктор принимает

std::map<std::string, std::shared_ptr<Base>> & 

и вы передаете:

std::map<std::string, std::shared_ptr<Derived>> 

Аргумент, который является именующей ссылкой типа T может быть удовлетворена только путем Lvalue типа T или типа, полученного из T (или типа с operator T&). Но std::map<std::string, std::shared_ptr<Derived>> на самом деле не наследует от std::map<std::string, std::shared_ptr<Base>> - и оба эти типа не связаны вообще - нет конструктора перекрестного типа для std::map.

Другими словами, только потому, что D является B вовсе не означает, что map<X, D> является map<X, B>. Таким образом, нет никакой ковариации типов в системе типа C++. Некоторые типы по крайней мере, позволяют построить Class<B> из Class<D> (например std::shared_ptr), но это не верно стандартных контейнеров (например, vector, map, ...)

Вам придется изменить lMap держать std::shared_ptr<Base> сек чтобы это работало. Он может внутренне удерживать std::shared_ptr<Derived> с - но типы map должны соответствовать.


Побочное примечание, в C++ 11 вам не нужно Uncopyable. Вы можете прямо указать delete следующие операции:

A(A const&) = delete; 
A& operator=(A const&) = delete; 
+0

Я вижу, что вы указываете, это очень ясно. Итак, если функция f принимает в качестве аргумента std :: shared_ptr , и я определяю std :: map > lMap. Я назначаю lMap [0] std :: shared_ptr . Невозможно использовать lMap [0] для f? – Canardini

+0

@Canardini Если 'f' принимает' shared_ptr ', то вы не можете передать 'shared_ptr ' ему, да. Как он узнает, что он на самом деле указывает на объект 'Derived'? – Barry

+0

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