2016-05-27 9 views
1

Ich habe ein Problem, mein nicht kopierbares Objekt zu konstruieren. Lassen Sie folgendes Beispiel:Nicht kopierbares Objekt, Karte und shared_ptr: Fehler im Kopierkonstruktor

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

Wenn ich mein Objekt A annehmen, nicht kopierbaren zu sein, ist es nicht einen Zeiger nicht work.As, ich mein Objekt A erwarten zu verstehen, dass Abgeleitet eine Base ist, sondern ich bekomme folgende Nachricht:

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>   ] 

Danke.

Antwort

3

Der Fehler hat nichts mit der Nichtkopierbarkeit von A zu tun und befindet sich tatsächlich nicht im Kopierkonstruktor, sondern im map Konstruktor. Der Fehler hat mit der Tatsache zu tun, dass A' Konstruktor ein

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

nimmt und Sie übergeben ein:

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

Ein Argument, das eine L-Wert Referenz vom Typ T kann nur durch einen L-Wert erfüllt werden vom Typ T oder von einem Typ, der sich von T ableitet (oder von einem Typ mit einem operator T&). Aber std::map<std::string, std::shared_ptr<Derived>> erbt tatsächlich nicht von std::map<std::string, std::shared_ptr<Base>> - noch sind die beiden Typen überhaupt verwandt - es gibt keinen Kreuztypenkonstruktor für std::map.

Mit anderen Worten, nur weil ein D ein B ist, bedeutet nicht, dass ein map<X, D> ein map<X, B> ist. Auf diese Weise gibt es im C++ - Typsystem keine Kovarianz von Typen. Einige Arten zumindest können Sie einen Class<B> von einem Class<D> (zB std::shared_ptr) konstruieren, aber das ist nicht wahr, der Standardcontainer (zB vector, map, ...)

Sie müssen lMap ändern std::shared_ptr<Base> s zu halten damit das funktioniert. Es kann intern std::shared_ptr<Derived> s halten - aber die map Typen müssen übereinstimmen.


Side-Note, in C++ 11 Sie nicht Uncopyable benötigen. Sie können einfach explizit delete diese Operationen:

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

Ich sehe Sie Punkt, es ist sehr klar. Also, wenn eine Funktion f als Argument ein std :: shared_ptr nimmt, und ich definiere std :: map > lMap. Ich ordne lMap [0] ein std :: shared_ptr zu. Es ist nicht möglich, lMap [0] für f zu verwenden. – Canardini

+0

@Canardini Wenn 'f' ein' shared_ptr 'nimmt, dann können Sie kein' shared_ptr 'daran übergeben, ja. Woher sollte es wissen, dass es tatsächlich auf ein "Abgeleitetes" Objekt zeigt? – Barry

+0

Richtig, das habe ich aus Ihrer Antwort verstanden. Ich habe versucht, den dynamischen Cast-Zeiger zu verwenden, das Problem konnte nicht gelöst werden. – Canardini