2013-05-23 3 views
3

Учитывая следующую программу:Инстанцирования типа станд :: shared_ptr потеря Const

#include <memory> 

template <typename T> 
class SharedPtr : public std::shared_ptr<T> 
{ 
    typedef std::shared_ptr<T> Impl; 
    template<typename U> friend class SharedPtr; 
    SharedPtr(Impl const& other) : Impl(other) {} 
public: 
    SharedPtr(T* newed_ptr) : Impl(newed_ptr) {} 
    SharedPtr(SharedPtr const& other) throw() : Impl(other) {} 
    template <typename U> SharedPtr(SharedPtr<U> const& other) throw() : Impl(other) {} 

    template <typename U> SharedPtr<U> DynamicCast() const throw() 
    { 
     return SharedPtr<U>(std::dynamic_pointer_cast<U>(*this)); 
    } 
}; 

template<typename T> class Handle : public SharedPtr<T const> 
{ 
    typedef SharedPtr<T const> Base; 
    template <typename U> friend class Handle; 
public: 
    explicit Handle(T const* pObject = 0) : Base(pObject) {} 
    Handle(SharedPtr<T> const& src) : Base(src) {} 
    template <typename Derived> 
    Handle(Handle<Derived> const& other) : Base(other) {} 
    template <typename Derived> 
    Handle<Derived> DynamicCast() const throw() { 
     SharedPtr<Derived const> tmp = this->Base::template DynamicCast<Derived const>(); 
     return Handle<Derived>(tmp); 
    } 
}; 

class B { public: virtual ~B() {} }; 
class D : public B{}; 

void 
testit() 
{ 
    Handle<D> p(new D); 
    Handle<B> p1(p); 
    Handle<D> p2(p1.DynamicCast<D>()); 
} 

я получаю следующие ошибки (от г ++ 4.7.2):

noX.cc: In instantiation of ‘SharedPtr<T>::SharedPtr(const SharedPtr<U>&) [with U = const D; T = D]’: 
noX.cc|33 col 37| required from ‘Handle<Derived> Handle<T>::DynamicCast() const [with Derived = D; T = B]’ 
noX.cc|45 col 37| required from here 
noX.cc|13 col 88| error: no matching function for call to ‘std::shared_ptr<D>::shared_ptr(const SharedPtr<const D>&)’ 
noX.cc|13 col 88| note: candidates are: 

и длинный список кандидатов , Microsoft (MSVC 11) дает подобное сообщение, поэтому я предполагаю, что ошибка в моем коде, а - не ошибка компилятора.

Очевидно, что я не ожидаю, чтобы иметь возможность конвертировать SharedPtr<D const> к SharedPtr<D> (или std::shared_ptr<D const> к std::shared_ptr<D>, который , что Microsoft жалуется). Но откуда берутся SharedPtr<D>? Я не вижу ничего в этом коде, который должен создать любой умный указатель любого типа неконстантному.

+0

@LucDanton Да. Это была ошибка. Я просто не искал нужного места. –

+0

Другой вопрос для вас? Что вы пытаетесь выполнить с помощью этих классов? Просто любопытно ... – ForeverLearning

+0

@Dilip Обеспечьте безопасный интерфейс функционального стиля. Они частично исторически обусловлены, но в самом коде они, конечно, значительно сложнее. В частности, это 'template ' class SharedPtr' с частичными специализациями, так что фактическая реализация 'SharedPtr' зависит от того, поддерживает ли указательный класс класс инвазивного подсчета ссылок или нет (и долгосрочный, чтобы избавиться от неинвазивного подсчета ссылок, поскольку это слишком опасно). –

ответ

3

На первый взгляд это выглядит как SharedPtr<Derived> объект неявным создан для Handle(SharedPtr<T> const& src) вызова на return Handle<Derived>(tmp);

+0

Хорошо пятнистый. Я сменил конструктор 'SharedPtr' на' Handle (SharedPtr const & src) ', и теперь код кода компилируется. (Я должен увидеть, исправляет ли это проблему в реальном коде, но 'SharedPtr ' явно является ошибкой. –

3
template<typename T> class Handle : public SharedPtr<T const> 
{ 
    Handle(SharedPtr<T> const& src) : Base(src) {} 

    Handle<Derived> DynamicCast() const throw() { 
     SharedPtr<Derived const> tmp = this->Base::template DynamicCast<Derived const>(); 
     return Handle<Derived>(tmp); 
    } 

Ваше возвращение Handle где Т типа Derived без Уст. T в SharedPtr<T> имеет тип Derived const.

4

Этот конструктор:

Handle(SharedPtr<T> const& src) : Base(src) {} 

опирается на неявное преобразование из SharedPtr<T> в SharedPtr<T const> (т.е. Base) , Но здесь:

return Handle<Derived>(tmp); 

Вы хотите SharedPtr<T const> ->Handle<T> преобразования, хотя единственный вероятный кандидат является конструктором с SharedPtr<T>. Одно из решений заключается в том, чтобы изменить это на:

Handle(Base const& src) : Base(src) {} 

«перемещение» неявного преобразования в вызывающие абоненты, если необходимо.